Search uses ConstantsTrait
The keys of the model-level ArangoSearch declaration (`AQL::VIEW`) and the synthetic relevance sort key.
A Documents model declares an ArangoSearch View through the AQL::VIEW
block; when present, the ?search= parameter switches from the simple
LIKE sweep to an index-accelerated, relevance-ranked SEARCH against
the View:
AQL::VIEW =>
[
Search::NAME => 'placesView' , // the View name (required)
Search::ANALYZER => 'text_fr' , // Analyzer of the searched fields
Search::FIELDS => // field => boost (or array of per-field options)
[
'name' => [ Search::BOOST => 3 , Search::FUZZY => 1 ] , // text : typo-tolerant
'code' => [ Search::BOOST => 1 , Search::FUZZY => 0 ] , // code : exact match
] ,
Search::PHRASE => true , // exact-phrase bonus (boost ×2)
Search::FUZZY => 1 , // View-level Levenshtein tolerance (0 = off, override per field)
]
Tags
Table of Contents
Constants
- ANALYZER : string = 'analyzer'
- The Analyzer applied to the searched fields (indexing and querying side).
- BOOST : string = 'boost'
- A per-field boost weight (also accepted as the plain numeric value of a `FIELDS` entry). Defaults to `1`.
- FIELDS : string = 'fields'
- The searched fields: `field => boost` (or `field => [ Search::BOOST => n, Search::FUZZY => d ]` to carry per-field options).
- FUZZY : string = 'fuzzy'
- Levenshtein tolerance: the maximum edit distance for fuzzy term matching (`LEVENSHTEIN_MATCH`), a valid distance being `0`–`4`. `0` (default) disables fuzzy matching.
- KEY : string = 'key'
- The searched field name carried by an array entry of the `AQL::SEARCHABLE` list, so the list stays homogeneous (no mixed numeric/string keys) while an entry carries per-field options:
- LANG : string = 'lang'
- The locale a searched field holds, marking it as a localized variant (e.g. `'description.fr' => [ Search::LANG => 'fr' ]`). When the request carries an active language (`?lang=`), only fields whose `Search::LANG` matches — plus the fields that declare none — take part in the `SEARCH`; without `?lang=` every field is searched. If the active language matches no field, the filter is ignored and all fields are searched (never an empty `SEARCH`). A field with no `LANG` key is locale-agnostic and is always searched.
- NAME : string = 'name'
- The name of the ArangoSearch View (required to activate the View search).
- NGRAM : string = 'ngram'
- Declares, on a {@see FIELDS} entry, an `ngram` Analyzer queried through `NGRAM_MATCH` (a **similarity threshold**) rather than the loose `IN TOKENS` of {@see ANALYZER} — the precise way to power substring / autocomplete search. The field is indexed with this Analyzer (merged into the link) and the query emits its own `ANALYZER(NGRAM_MATCH(…))` branch.
- PHRASE : string = 'phrase'
- Whether to add an exact-phrase bonus: when `true`, a `PHRASE()` match on a field weighs twice the field boost, ranking exact phrases first.
- REQUIRES : string = 'requires'
- The permission subject(s) required to search — a string or a list (OR semantics), mirroring {@see \oihana\arango\enums\Field::REQUIRES} for projections. Declared at **two levels**:
- SCORE : string = 'score'
- The synthetic relevance sort key exposed to `?sort=` when a View search is active (`?sort=-score`, `?sort=score,name`, …) — the counterpart of the `distance` key driven by `?near=`. Resolves to `BM25(doc)`.
- THRESHOLD : string = 'threshold'
- The `NGRAM_MATCH` similarity threshold, an inner key of a {@see NGRAM} map — a float in `[0.0, 1.0]` (the fraction of the query's n-grams that must be found). Higher = stricter. Absent / `null` falls back to the server default (`0.7`). Out-of-range values are rejected.
Constants
ANALYZER
The Analyzer applied to the searched fields (indexing and querying side).
public
string
ANALYZER
= 'analyzer'
Defaults to identity — declare a text Analyzer (text_fr, text_en, …)
for linguistic matching.
Declared at the View level it applies to every searched field; declared
inside a FIELDS entry it overrides that level for the field — so a
single View can index a text_fr body and a text_en body, each queried
through its own Analyzer. Since the Analyzer is fixed at indexing time,
a per-field override is reflected both in the View link and in the query.
A per-field entry also accepts a list of Analyzers (['text_fr', 'autocomplete']): the field is then indexed through every one of them and
the query matches under each (one ANALYZER(...) branch per Analyzer,
OR-ed). This indexes the same field several ways at once — e.g. a text
recipe for whole-word search plus an ngram recipe for autocomplete. The
View-level value stays a single Analyzer (the inherited default).
BOOST
A per-field boost weight (also accepted as the plain numeric value of a `FIELDS` entry). Defaults to `1`.
public
string
BOOST
= 'boost'
FIELDS
The searched fields: `field => boost` (or `field => [ Search::BOOST => n, Search::FUZZY => d ]` to carry per-field options).
public
string
FIELDS
= 'fields'
Falls back to the model's AQL::SEARCHABLE list (boost 1) when omitted.
FUZZY
Levenshtein tolerance: the maximum edit distance for fuzzy term matching (`LEVENSHTEIN_MATCH`), a valid distance being `0`–`4`. `0` (default) disables fuzzy matching.
public
string
FUZZY
= 'fuzzy'
Declared at the View level it applies to every searched field; declared
inside a FIELDS entry it overrides that level for the field — an
explicit 0 opts a field out (e.g. an identifier) while the rest of the
View stays typo-tolerant. A field with no FUZZY key inherits the
View-level value.
KEY
The searched field name carried by an array entry of the `AQL::SEARCHABLE` list, so the list stays homogeneous (no mixed numeric/string keys) while an entry carries per-field options:
public
string
KEY
= 'key'
AQL::SEARCHABLE =>
[
'name' , // public field (plain string)
[ Search::KEY => 'salary' , Search::REQUIRES => 'hr:salary' ], // gated field
]
Only meaningful inside AQL::SEARCHABLE array entries; Search::FIELDS
keeps its map form (field => options) where the field is the key.
LANG
The locale a searched field holds, marking it as a localized variant (e.g. `'description.fr' => [ Search::LANG => 'fr' ]`). When the request carries an active language (`?lang=`), only fields whose `Search::LANG` matches — plus the fields that declare none — take part in the `SEARCH`; without `?lang=` every field is searched. If the active language matches no field, the filter is ignored and all fields are searched (never an empty `SEARCH`). A field with no `LANG` key is locale-agnostic and is always searched.
public
string
LANG
= 'lang'
NAME
The name of the ArangoSearch View (required to activate the View search).
public
string
NAME
= 'name'
NGRAM
Declares, on a {@see FIELDS} entry, an `ngram` Analyzer queried through `NGRAM_MATCH` (a **similarity threshold**) rather than the loose `IN TOKENS` of {@see ANALYZER} — the precise way to power substring / autocomplete search. The field is indexed with this Analyzer (merged into the link) and the query emits its own `ANALYZER(NGRAM_MATCH(…))` branch.
public
string
NGRAM
= 'ngram'
Two forms: the analyzer name alone (the threshold falls back to the server
default 0.7), or a map carrying the analyzer and an explicit threshold:
Search::NGRAM => 'autocomplete' // default threshold
Search::NGRAM => [ Search::ANALYZER => 'autocomplete', Search::THRESHOLD => 0.6 ]
It is disjoint from ANALYZER: put the text recipes under
ANALYZER (whole-word, IN TOKENS, BM25) and the ngram recipe here. The
field's BOOST applies to the branch; FUZZY / PHRASE do
not. NGRAM_MATCH wants an ngram Analyzer declared with min == max and
preserveOriginal: false.
PHRASE
Whether to add an exact-phrase bonus: when `true`, a `PHRASE()` match on a field weighs twice the field boost, ranking exact phrases first.
public
string
PHRASE
= 'phrase'
Declared at the View level it applies to every searched field; declared
inside a FIELDS entry it overrides that level for the field — an
explicit false opts a field out while the rest of the View keeps the
bonus. A field with no PHRASE key inherits the View-level value.
PHRASE() requires the field Analyzer to expose the position and
frequency features.
REQUIRES
The permission subject(s) required to search — a string or a list (OR semantics), mirroring {@see \oihana\arango\enums\Field::REQUIRES} for projections. Declared at **two levels**:
public
string
REQUIRES
= 'requires'
- on the
AQL::VIEWblock → gates the whole search (every field): a denied subject yields aSEARCHthat matches nothing, whatever the per-field declarations; - inside a FIELDS entry → gates that single field.
The same key gates the classic LIKE sweep too: a AQL::SEARCHABLE entry
may carry it (via KEY) to make a field searchable only when granted.
The two levels combine with AND (the request must satisfy the
View-level requirement and the field's own) — unlike the other
per-field facets, where a field value overrides the View level. Within a
single list the subjects combine with OR. A level with no REQUIRES adds
no constraint; a field is always searchable when neither level gates it.
The decision is delegated to the request authorizer (Arango::AUTHORIZER,
see isAuthorized()). With no authorizer
injected the gate falls open (authorization layer disabled). If permissions
remove every searched field, the SEARCH matches nothing — it never falls
back to searching everything.
SCORE
The synthetic relevance sort key exposed to `?sort=` when a View search is active (`?sort=-score`, `?sort=score,name`, …) — the counterpart of the `distance` key driven by `?near=`. Resolves to `BM25(doc)`.
public
string
SCORE
= 'score'
THRESHOLD
The `NGRAM_MATCH` similarity threshold, an inner key of a {@see NGRAM} map — a float in `[0.0, 1.0]` (the fraction of the query's n-grams that must be found). Higher = stricter. Absent / `null` falls back to the server default (`0.7`). Out-of-range values are rejected.
public
string
THRESHOLD
= 'threshold'