Skip to main content

Query semantics and limitations

Constraint results depend on value types, numeric precision, and the matching rules of each operator. Indexes can accelerate a query, while vector-search options also determine which candidates are considered. The examples below illustrate these distinctions with small datasets.

Stored and evaluated types​

A native property has one enforced physical type within a class. After storing p: 1, storing p: "1" on another record in the same class fails. A JSON property can hold differently typed payloads while retaining the JSON storage type. Its payloads 1, "1" and true remain different values.

This expression selects record 0 before comparing its JSON payload with the number 1:

["all", ["$rid", "==", 0], ["$p", "==", 1]]

An unguarded numeric comparison over incompatible JSON payloads raises a type error. is_missing matches both JSON null and an absent property. An explicit type index preserves these results; it indexes storage types and does not convert JSON into a native numeric or string property.

For an ordinary list request, a small limit can satisfy the page before a later row’s error is encountered. A successful limited query therefore does not establish that every object can be evaluated. An exact count requires all matches before pagination. Page-local aggregates may also encounter errors outside the returned page; see constraints for evaluation and error rules.

Precision and arrays​

A JSON literal preserves the integer 9007199254740993 for an exact membership comparison:

[{"json": 9007199254740993}, "in", "$j"]

This value remains distinct from 9007199254740992, with or without an array index. Preservation for membership does not make it a representable finite scalar number: ["$p", "is_finite"] is false for that JSON integer.

List membership means all-element containment. An empty left list is contained in every right list. ["$a", "in", {"array": [1]}] matches an empty array, but does not match [1, "1", true]. Strings and booleans are not coerced to numbers.

Text operators have different normalization​

icontains applies full case folding: searching for STRASSE matches both Straße and STRASSE. iregex follows the regex engine’s case matching; ^strasse$ matches STRASSE but not Straße.

Fulltext uses compatibility normalization, so a query for abc matches both ABC and abc. Similarity does not apply that fulltext normalization; a similarity score of 1 against abc selects only the latter here. Fulltext requires a suitable fulltext index and native string values. A JSON-wrapped string remains ineligible even if an index definition exists.

A full-text filter does not automatically order results by relevance. In this query, sort.expression orders matches by their score, and results.expressions includes that score in the response:

score = {"fulltext": ["$text", "abc"]}
query = [{"FindEntity": {
"with_class": "YourClass",
"constraints": [score, ">", 0],
"sort": {"expression": score, "order": "descending"},
"results": {"list": ["rid"], "expressions": {"score": score}}
}}]

Descriptor filtering and index coverage​

The vector example uses a two-dimensional Flat/L2 index with two close but ineligible descriptors and two farther eligible descriptors. With k=2:

Results by search mode

Request

Returned IDs

Filter first (default), before fresh insertion

[2, 3]

knn_first: true

[]: the two global neighbors fail the filter

Filter first, after inserting a closer eligible descriptor

[4, 2]

Same search with indexed_results_only: true

[2, 3]: the new descriptor has not been indexed

The example inserts the descriptor and runs both follow-up queries in one transaction to demonstrate searching before the new descriptor is indexed. knn_first may return fewer than k even when enough eligible descriptors exist. It is not interchangeable with exact search over the filtered set.

These results use exact search with the Flat engine. With approximate search through HNSW, IVF, or ACORN, recall depends on the data, dimensions, filters, index parameters, and update pattern. An exact search over the same eligible objects provides a comparison for measuring recall. FindDescriptor describes the search modes.

Running the examples​

The Python examples create uniquely named sample datasets, check the outcomes described above, and remove their records and property indexes. Run them against a disposable database with the aperturedb Python package installed. Supply credentials through ADB_USER and ADB_PASSWORD. For a local server without TLS:

python query_semantics.py --host 127.0.0.1 --port 55555 --no-ssl --output results.json

Omit --no-ssl when the server uses TLS. The result file contains the checked outcomes; any unexpected result or missing expected error fails the script. No existing class, property index, or descriptor set is reused. Empty class definitions may remain after the sample records are removed.