---
title: "AEL string, BLOB, and HLL functions"
description: "AEL reference: method-style path functions on STRING, BLOB, and HLL receivers, including regex literals and write-policy postfix flags."
---

# AEL string, BLOB, and HLL functions

> For the complete documentation index see: [llms.txt](https://aerospike.com/docs/llms.txt)
> 
> All documentation pages available in markdown.

Reference page: part of the [AEL reference](https://aerospike.com/docs/develop/client/sdk/concepts/ael/reference). Covers method-style functions on `STRING`, `BLOB`, and `HLL` receivers. See [Applies to](https://aerospike.com/docs/develop/client/sdk/concepts/ael/reference#applies-to) on the overview page for SDK and Database version requirements.

## String path functions

Method-style on a **STRING** receiver may be a bin root (`$.str.…`), a nested or pathed string value (`$.m.x.…`), or a chained string result. Positions and lengths are Unicode code points.

`toInt()` and `toFloat()` share names with [path read terminals](https://aerospike.com/docs/develop/client/sdk/concepts/ael/reference/functions#path-read-terminals). On bins whose type is not already resolved, pin `:STRING` before the call, for example `$.code:STRING.toInt()`, so the compiler selects string parsing rather than a numeric cast.

::: string modify terminals and 
Functions that return a new `STRING` and modify the underlying value (`upper`, `lower`, `trim`, `splice`, `overwrite`, and all of [Modify (return new string)](#modify-return-new-string)) are write terminals when used on a pathed receiver (`$.m.x.…`). On such a path they accept `:NO_FAIL`: if a collection data type (CDT) context segment on the path is absent in the bin, the write is a no-op that reports success and the original bin is left unchanged — there is no error to indicate the write didn’t happen. Read terminals (`strlen`, `find`, `substr`, `charAt`, `toInt`, and so on) do not accept `:NO_FAIL`. The flag is valid only on a pathed string modify, not on a bare bin (`$.str.upper()`) or a parenthesised value receiver (`(expr).upper()`), where there is no multi-segment CDT context. `:NO_FAIL` does not suppress parse errors, invalid flag placement, or op-specific failures such as `overwrite` with an offset past the end.
:::

### Read and transform

| Function | Return | Description |
| --- | --- | --- |
| `strlen()` | `INT` | Character count |
| `substr(from: [, to:])` | `STRING` | Substring; `from` inclusive; `to` exclusive if present; negative indices count from end; invalid range → empty string |
| `charAt(index:)` | `STRING` | Single Unicode codepoint at index; index clamped to `[0, length]`; past end → empty string |
| `upper()` / `lower()` / `caseFold()` / `normalizeNFC()` | `STRING` | Case and Unicode NFC normalization |
| `trim()` / `trimStart()` / `trimEnd()` | `STRING` | Trim Unicode whitespace at both ends / leading / trailing |
| `find(needle:, occurrence:)` | `INT` | Position of nth occurrence; `-1` if not found; `occurrence` `0` → error; `occurrence` `-1` selects the last match; treats precomposed and decomposed Unicode forms as equal |
| `contains(needle:)` | `TRILEAN` | Substring test; same canonical-equivalence rules as `find()` |
| `padStart(length:, pad:)` / `padEnd(length:, pad:)` | `STRING` | Pad to minimum length; pad string may be multi-character |
| `toInt()` / `toFloat()` | numeric | Parse numeric string |
| `regexReplace(pattern:, replace:)` | `STRING` | Perl-compatible regex replace; replaces the first match by default, or every match when `pattern:` carries the `g` (global) flag. `pattern:` must be a [regex literal](#regex-literals), not a quoted string. `$n` in `replace:` references capture groups |
| `startsWith(prefix)` / `endsWith(suffix)` | `TRILEAN` | Prefix / suffix test |
| `split(separator)` | `LIST` | Split to list of strings |
| `repeat(count)` | `STRING` | Repeat string |
| `isUpper()` / `isLower()` | `TRILEAN` | All characters uppercase / lowercase |
| `isNumeric()` | `TRILEAN` | Numeric string test |
| `bytesLength()` | `INT` | Length in bytes (as opposed to `strlen()`’s codepoint count) |
| `toBlob()` | `BLOB` | String to blob |
| `b64Decode()` | `BLOB` | Base64 string to blob; fails on invalid base64 |

```plaintext
/* Replace only the first run of digits with '#' (default: first match only): */

$.sku.regexReplace(pattern: /[0-9]+/, replace: '#')

/* Replace every run of digits with '#' (g flag opts in to global replace): */

$.sku.regexReplace(pattern: /[0-9]+/g, replace: '#')

/* Case-insensitive whole-word match, redacting the first match: */

$.logLine.regexReplace(pattern: /\berror\b/i, replace: '[REDACTED]')

/* Reformat 'Last, First' to 'First Last' using capture groups: */

$.name.regexReplace(pattern: /^(\w+),\s*(\w+)$/, replace: '$2 $1')
```

### Regex literals

`/pattern/` or `/pattern/flags`, using Perl-compatible regex syntax. Flags compose by concatenation, for example `/pat/im`. A regex literal must appear directly in the expression: it cannot come from a bin or variable.

| Flag | Meaning | Valid on |
| --- | --- | --- |
| `i` | Case-insensitive (Unicode case folding) | `=~` and `regexReplace()` |
| `m` | `^` and `$` match line boundaries | `=~` and `regexReplace()` |
| `s` | Dot matches newlines | `=~` and `regexReplace()` |
| `g` | Global: replace every match instead of only the first | `regexReplace()` only |

Only `i`, `m`, `s`, and `g` are supported. `g` is valid only on `regexReplace()` — using it with `=~` is a parse error.

### Modify (return new string)

| Function | Return | Description |
| --- | --- | --- |
| `splice(offset:, value:)` | `STRING` | Insert at offset; named `splice` (not `insert`) to avoid collision with list/map `insert()`; offset clamped to `[0, length]` — past end appends, for example `splice(offset: 4, value: "and")` on `"yes"` → `"yesand"` |
| `overwrite(offset:, value:)` | `STRING` | Overwrite at offset; offset past end → error (not suppressed by `:NO_FAIL`) |
| `snip(from: [, to:])` | `STRING` | Remove range; `from >= to` → unchanged |
| `replace(find:, replace:)` | `STRING` | First occurrence; treats precomposed and decomposed Unicode forms as equal |
| `replaceAll(find:, replace:)` | `STRING` | All occurrences; same canonical-equivalence rules as `replace()` |

```plaintext
$.msg.splice(offset: 0, value: '[URGENT] ')

$.path.snip(from: 5)

$.m.x.upper():NO_FAIL                                        /* :NO_FAIL applies to absent path only */

$.m.x.overwrite(offset: 12, value: '-patched-'):NO_FAIL      /* :NO_FAIL applies to absent path only; offset past end still errors */

$.m.x.splice(offset: 12, value: '-patched-'):NO_FAIL         /* tolerant offset (clamp/append); insert, not overwrite */
```

### Cross-type string conversions

| Function | Receiver type | Return | Description |
| --- | --- | --- | --- |
| `toString()` | `INT`, `FLOAT`, `BOOL`, `STRING`, `BLOB` | `STRING` | Format as string; `STRING` is identity; `BLOB` must be valid UTF-8 |

On a bin path, pin or infer the receiver type before calling, for example `$.amount:INT.toString()`. Record metadata uses the [parenthesis rule](https://aerospike.com/docs/develop/client/sdk/concepts/ael/reference/paths#parenthesised-expressions), for example `($.recordSize()).toString()`, not `$.recordSize().toString()`.

### List string function

CDT list operation that joins list elements into one string:

| Function | Return | Description |
| --- | --- | --- |
| `$.list.join(separator)` | `STRING` | Join list elements with separator |

### Chaining

String methods that return `STRING` may chain left-to-right (`$.email.trim().lower()`). A method that returns `INT` or `TRILEAN` ends the string-method chain — no further `.stringMethod()` may follow it. Use that result in a comparison, arithmetic, or other surrounding expression instead.

```plaintext
/* Valid: each call returns STRING */

$.sku.trim().upper().replace(find: '-', replace: '_')

/* Parse error: find() returns INT; .replace() cannot follow */

$.sku.find(needle: '-', occurrence: 1).replace(find: '_', replace: '.')

/* Valid: INT result used in an expression, not chained to another string method */

$.sku.find(needle: '-', occurrence: 1) == 3

$.email.strlen() > 0
```

## BLOB (bit) path functions

Method-style on a `BLOB` receiver. Offsets and sizes are in bits unless noted as byte offset.

### Read

| Function | Return | Description |
| --- | --- | --- |
| `bitGet(offset:, size:)` | `BLOB` | Extract bit range |
| `b64Encode()` | `STRING` | Base64-encode the blob |
| `bitCount(offset:, size:)` | `INT` | Count set bits in range |
| `bitLscan(offset:, size:, value:)` / `bitRscan(offset:, size:, value:)` | `INT` | Scan left/right for bit value |
| `bitGetInt(offset:, size: [, signed:])` | `INT` | Extract as integer; `signed` default `false` |

::: b64encode() — outside the developer sdk surface
`b64Encode()` is defined by the AEL grammar but not yet accepted by the Developer SDK. Calling it fails when the server parses the request — see [Malformed AEL text](https://aerospike.com/docs/develop/client/sdk/concepts/error-handling#malformed-ael-text). There is no local check before the request is sent.
:::

### Modify (return modified BLOB)

| Function | Return | Description |
| --- | --- | --- |
| `bitResize(byteSize:)` | `BLOB` | Resize to byte length |
| `bitInsert(byteOffset:, value:)` / `bitRemove(byteOffset:, byteSize:)` | `BLOB` | Insert / remove bytes |
| `bitSet(offset:, size:, value:)` / `bitOr(…)` / `bitXor(…)` / `bitAnd(…)` / `bitNot(offset:, size:)` | `BLOB` | Bitwise ops on range |
| `bitLshift(offset:, size:, shift:)` / `bitRshift(offset:, size:, shift:)` | `BLOB` | Shift range |
| `bitAdd(offset:, size:, value: [, signed:])` / `bitSubtract(…)` | `BLOB` | Add / subtract in range; overflow fails |
| `bitSetInt(offset:, size:, value:)` | `BLOB` | Write integer in range |

Write-policy postfix flags: bit modify ops accept `:CREATE_ONLY`, `:UPDATE_ONLY`, `:NO_FAIL`, and `:PARTIAL` where listed in the following table. These flags control whether the bin may be created or updated, not individual bit ranges within an existing blob. Bit read ops (preceding section) reject all write-policy flags.

`:CREATE_ONLY` and `:UPDATE_ONLY` are mutually exclusive. `:PARTIAL` on BLOB bit ops does **not** imply `:NO_FAIL`; it means clip the operation to the end of the blob and apply it (see the flag table in [Postfix flags](https://aerospike.com/docs/develop/client/sdk/concepts/ael/reference/control-and-flags#postfix-flags)). Combine `:NO_FAIL` with `:CREATE_ONLY` or `:UPDATE_ONLY` when a conflict should be ignored, for example `bitResize(byteSize: 4):CREATE_ONLY:NO_FAIL`. Combine `:PARTIAL` and `:NO_FAIL` explicitly when both clip tolerance and ignored flag conflicts are needed.

Valid flags by op — flags not listed for an op are invalid:

| Op | `:CREATE_ONLY` | `:UPDATE_ONLY` | `:NO_FAIL` | `:PARTIAL` |
| --- | :-: | :-: | :-: | :-: |
| `bitResize` | ✓ | ✓ | ✓ | — |
| `bitInsert` | ✓ | ✓ | ✓ | — |
| `bitRemove` | — | ✓ | ✓ | ✓ |
| `bitSet`, `bitOr`, `bitXor`, `bitAnd`, `bitNot` | — | ✓ | ✓ | ✓ |
| `bitLshift`, `bitRshift` | — | ✓ | ✓ | ✓ |
| `bitAdd`, `bitSubtract`, `bitSetInt` | — | ✓ | ✓ | — |

Only `bitResize` and `bitInsert` can create a missing bin; `:CREATE_ONLY` applies only to those two. All other modify ops require an existing blob unless `:NO_FAIL` suppresses the error (`:PARTIAL` alone does not).

```plaintext
$.header.bitResize(byteSize: 4):CREATE_ONLY              /* create bin only if absent */

$.header.bitInsert(byteOffset: 0, value: x'01'):UPDATE_ONLY

$.header.bitSet(offset: 8, size: 8, value: x'01'):UPDATE_ONLY:NO_FAIL

$.header.bitRemove(byteOffset: 0, byteSize: 2):PARTIAL
```

Integer bitwise operators (`&`, `|`, `^`, `~`, `<<`, `>>`, `>>>`) apply to whole 64-bit `INT` values, not BLOB bit ranges. See [Integer bitwise](https://aerospike.com/docs/develop/client/sdk/concepts/ael/reference/operators#integer-bitwise).

## HLL path functions

HLL read path functions operate on bins typed as `HLL`. They mirror the server [HyperLogLog read operations](https://aerospike.com/docs/develop/data-types/hll) and the [HLL expressions](https://aerospike.com/docs/develop/expressions/hll) reference (`hll_get_count`, `hll_get_union_count`, and so on). Use them in `where(...)` filters and other Boolean AEL contexts.

The receiver path (`$.h` in the following tables) is the HLL bin the function runs against.

### Read functions

| Function | Parameters | Returns | Description |
| --- | --- | --- | --- |
| `$.h.hllCount()` | — | `INT` | Estimated number of unique entries in the sketch. Uses the cached count; see `refresh_count` on the [underlying HLL type](https://aerospike.com/docs/develop/data-types/hll) if the bin was modified since the last count. |
| `$.h.hllDescribe()` | — | `LIST` | Two-element list `[index_bit_count, min_hash_bit_count]` describing the sketch precision. |
| `$.h.hllMayContain(list)` | `LIST` of values to check | `INT` (`1` or `0`) | Returns `1` if the sketch **may** contain all listed elements (probabilistic membership test), otherwise `0`. |
| `$.h.hllUnion(peer)` | HLL bin path (single peer) | `HLL` | HLL value that is the union of the receiver bin and `peer`. |
| `$.h.hllUnionCount(peer)` | HLL bin path (single peer) | `INT` | Estimated cardinality of the union of the receiver bin and `peer`. |
| `$.h.hllIntersectCount(peer)` | HLL bin path (single peer) | `INT` | Estimated cardinality of the intersection of the receiver bin and `peer`. The underlying feature allows more than two HLLs to participate when minhash bits are enabled. That isn’t reachable from AEL today, because only one peer bin path can be passed per call. |
| `$.h.hllSimilarity(peer)` | HLL bin path (single peer) | `FLOAT` | Estimated [Jaccard similarity](https://en.wikipedia.org/wiki/Jaccard_index) between the receiver bin and `peer` (typically `0.0`–`1.0`). Same single-peer limitation as `hllIntersectCount`. |

For `hllUnion`, `hllUnionCount`, `hllIntersectCount`, and `hllSimilarity`, the argument is a single peer HLL bin path, such as `$.cohort_a`, not a list. [AEL collection literals are static only](https://aerospike.com/docs/develop/client/sdk/concepts/ael/reference/paths#parenthesised-expressions), so an explicit list like `[$.cohort_a, $.cohort_b]` is a parse error. There is no AEL syntax for combining three or more peer sketches in one call. To combine three or more peers, use the [HLL expressions](https://aerospike.com/docs/develop/expressions/hll) `Exp` builder directly, which accepts a list of peer HLLs.

```plaintext
$.h.hllCount() > 1000000

$.h.hllDescribe() == [14, 0]

$.h.hllMayContain(['alice', 'bob']) == 1

$.h.hllUnionCount($.cohort_a) > 50000

$.h.hllIntersectCount($.cohort_a) > 100

$.h.hllSimilarity($.cohort_a) >= 0.8

$.h.hllUnion($.cohort_a) == $.cohort_b
```

Compare estimated counts and similarities against thresholds in filters (for example high-cardinality segments or overlapping audiences). For modify-then-read composition with server expressions, see the [HLL expressions](https://aerospike.com/docs/develop/expressions/hll) reference.

### Modify

The Developer SDK does not support write-side HLL in AEL filters. In Python, initialize and update sketches with the builder API instead (`hll_init`, `hll_add` on `WriteBinBuilder`, both requiring a bin-direct receiver, not a nested path into an HLL value); see [Update records](https://aerospike.com/docs/develop/client/sdk/usage/update). The Java Developer SDK’s fluent builder has no `hllInit`/`hllAdd` equivalent in this release — use the classic client’s non-fluent `HLLOperation.init()` / `HLLOperation.add()` static factories instead. The grammar defines these modify functions for completeness with other AEL-based tools such as [Aerospike Voyager](https://aerospike.com/download/voyager/):

| Function | Parameters | Returns | Description |
| --- | --- | --- | --- |
| `$.h.hllInit(indexBits: [, minHashBits:])` | `INT` \[, `INT`\] | `HLL` | Create or reset the sketch with the given index (and optional minhash) bit counts. |
| `$.h.hllAdd(list [, indexBits: [, minHashBits:]])` | `LIST` \[, `INT` \[, `INT`\]\] | `HLL` | Add the list elements to the sketch. Optional `indexBits` / `minHashBits` create the bin if it does not exist. |

Create vs. update control (HLL): `hllInit` accepts `:CREATE_ONLY`, `:UPDATE_ONLY`, and `:NO_FAIL`. `hllAdd` accepts `:CREATE_ONLY` and `:NO_FAIL` only — `:UPDATE_ONLY` is a parse error on `hllAdd`. BLOB bit modify ops use the same flag names with per-op scope (see [Valid flags by op](#modify-return-modified-blob) earlier in this page). Map and list paths express create-only and update-only through verbs: single-key `insert(value)` / `update(value)` and bulk `insertItems(items)` / `updateItems(items)` (see [Path write terminals](https://aerospike.com/docs/develop/client/sdk/concepts/ael/reference/functions#path-write-terminals)).

| Flag | `hllInit` | `hllAdd` | Effect |
| --- | :-: | :-: | --- |
| _(default)_ | ✓ | ✓ | Upsert — create, re-init, or add as appropriate |
| `:CREATE_ONLY` | ✓ | ✓ | Fail if the operation would modify an existing bin |
| `:UPDATE_ONLY` | ✓ | — | Fail if the operation would create a new bin; **parse error** on `hllAdd` |
| `:NO_FAIL` | ✓ | ✓ | On a create/update conflict, succeed as a no-op instead of failing |

`:CREATE_ONLY` and `:UPDATE_ONLY` are mutually exclusive. Combine with `:NO_FAIL` when a conflict should be ignored, for example `hllInit(indexBits: 12):CREATE_ONLY:NO_FAIL`.

```plaintext
$.visitors.hllInit(indexBits: 12):CREATE_ONLY              /* init only if bin absent */

$.visitors.hllInit(indexBits: 12):UPDATE_ONLY              /* re-init only if bin exists */

$.visitors.hllAdd(['u1', 'u2']):CREATE_ONLY                /* add only when creating the bin */

$.visitors.hllAdd(['u1']):NO_FAIL                          /* tolerate missing bin / type mismatch */
```

## Next steps

-   [Control structures and postfix flags](https://aerospike.com/docs/develop/client/sdk/concepts/ael/reference/control-and-flags) — the full postfix flag semantics
-   [Functions and terminals](https://aerospike.com/docs/develop/client/sdk/concepts/ael/reference/functions) — record metadata and path terminals
-   [Operators](https://aerospike.com/docs/develop/client/sdk/concepts/ael/reference/operators) — comparison, logical, and arithmetic operators