Arcadic.FullText (Arcadic v0.7.0)

Copy Markdown View Source

ArcadeDB full-text search — tenant-blind FULL_TEXT (Lucene) index DDL and SEARCH_INDEX/SEARCH_FIELDS query builders, parallel to Arcadic.Vector.

The query text binds as the :q param (SQL); the index reference "Type[property]" and any analyzer class name are interpolated behind Arcadic.Identifier / a dotted-class-name allowlist (the only injection surfaces, closed by construction). A FULL_TEXT index retro-indexes rows that already exist when it is created (unlike LSM_SPARSE_VECTOR, which does not) — so there is no create-before-load ordering requirement. Full-text is HTTP-only SQL (Bolt is Cypher-only).

search/5's property_or_properties must match an existing FULL_TEXT index by NAME: a single-property index is Type[prop], a composite create_index(conn, T, [a, b]) is Type[a,b] (search it with the same list). SEARCH_INDEX on a ref with no matching index is a server SchemaException. search_fields/5 names the fields directly and needs no exact index-name match.

Summary

Functions

Creates a FULL_TEXT index on type over one property or a list of properties (idempotent — IF NOT EXISTS unless if_not_exists: false). opts: :if_not_exists (bool, default true), :analyzer (a friendly atom — :standard/:english/:keyword/:whitespace/:simple — or a Lucene FQCN string). Retro-indexes existing rows. Value-free on a bad identifier / analyzer / opt.

Creates a FULL_TEXT index, raising on error.

Drops a FULL_TEXT index (idempotent — IF EXISTS).

Drops a FULL_TEXT index, raising on error.

Builds the FULL_TEXT index reference "Type[p1,p2]", validating every identifier.

Full-text search via SEARCH_INDEX('Type[property]', :q). query binds as :q. opts: :limit (pos_integer → LIMIT :k), :with_score (project the BM25 $score and use the relevance-ranked {metadata:true} form). Returns whole records (+ "score" when :with_score).

Full-text search, returning rows or raising.

Full-text search via SEARCH_FIELDS(['p1','p2'…], :q) over a property list (all must be FULL_TEXT-indexed). Same opts/return shape as search/5 — but note SEARCH_FIELDS computes no relevance score: with :with_score it projects a constant score: 0.0 on every row (a shape-only column, not a ranking). Use search/5 (SEARCH_INDEX) for the BM25 $score.

Full-text search_fields, returning rows or raising.

Functions

create_index(conn, type, property_or_properties, opts \\ [])

@spec create_index(Arcadic.Conn.t(), String.t(), String.t() | [String.t()], keyword()) ::
  :ok | {:error, atom() | Exception.t()}

Creates a FULL_TEXT index on type over one property or a list of properties (idempotent — IF NOT EXISTS unless if_not_exists: false). opts: :if_not_exists (bool, default true), :analyzer (a friendly atom — :standard/:english/:keyword/:whitespace/:simple — or a Lucene FQCN string). Retro-indexes existing rows. Value-free on a bad identifier / analyzer / opt.

create_index!(conn, type, property_or_properties, opts \\ [])

@spec create_index!(
  Arcadic.Conn.t(),
  String.t(),
  String.t() | [String.t()],
  keyword()
) :: :ok

Creates a FULL_TEXT index, raising on error.

drop_index(conn, type, property_or_properties)

@spec drop_index(Arcadic.Conn.t(), String.t(), String.t() | [String.t()]) ::
  :ok | {:error, atom() | Exception.t()}

Drops a FULL_TEXT index (idempotent — IF EXISTS).

drop_index!(conn, type, property_or_properties)

@spec drop_index!(Arcadic.Conn.t(), String.t(), String.t() | [String.t()]) :: :ok

Drops a FULL_TEXT index, raising on error.

index_ref(type, property_or_properties)

@spec index_ref(String.t(), String.t() | [String.t()]) ::
  {:ok, String.t()} | {:error, :invalid_identifier}

Builds the FULL_TEXT index reference "Type[p1,p2]", validating every identifier.

search(conn, type, property_or_properties, query, opts \\ [])

@spec search(
  Arcadic.Conn.t(),
  String.t(),
  String.t() | [String.t()],
  String.t(),
  keyword()
) ::
  {:ok, [map()]} | {:error, atom() | Exception.t()}

Full-text search via SEARCH_INDEX('Type[property]', :q). query binds as :q. opts: :limit (pos_integer → LIMIT :k), :with_score (project the BM25 $score and use the relevance-ranked {metadata:true} form). Returns whole records (+ "score" when :with_score).

search!(conn, type, property_or_properties, query, opts \\ [])

@spec search!(
  Arcadic.Conn.t(),
  String.t(),
  String.t() | [String.t()],
  String.t(),
  keyword()
) :: [map()]

Full-text search, returning rows or raising.

search_fields(conn, type, properties, query, opts \\ [])

@spec search_fields(Arcadic.Conn.t(), String.t(), [String.t()], String.t(), keyword()) ::
  {:ok, [map()]} | {:error, atom() | Exception.t()}

Full-text search via SEARCH_FIELDS(['p1','p2'…], :q) over a property list (all must be FULL_TEXT-indexed). Same opts/return shape as search/5 — but note SEARCH_FIELDS computes no relevance score: with :with_score it projects a constant score: 0.0 on every row (a shape-only column, not a ranking). Use search/5 (SEARCH_INDEX) for the BM25 $score.

search_fields!(conn, type, properties, query, opts \\ [])

@spec search_fields!(
  Arcadic.Conn.t(),
  String.t(),
  [String.t()],
  String.t(),
  keyword()
) :: [map()]

Full-text search_fields, returning rows or raising.