API リファレンス
Index
Laurus 検索エンジンをラップするメインクラスです。
Laurus::Index.new(path: nil, schema: nil, wal_sync_policy: nil, commit_policy: nil)
コンストラクタ
| パラメータ | 型 | デフォルト | 説明 |
|---|---|---|---|
path: | String | nil | nil | 永続ストレージのディレクトリパス。nil の場合はインメモリインデックスを作成します。指定した場合、そのディレクトリは laurus-cli create index/--index-dir と同じ <path>/schema.toml + <path>/store/ というレイアウトに従うため、ここで作成したインデックスは CLI からも開けます(逆も同様)。詳細は下記を参照。 |
schema: | Schema | nil | nil | スキーマ定義。新規にファイルベース(またはインメモリ)インデックスを作成する場合のみ意味を持ちます。既存のファイルベースインデックスを再オープンする場合は省略する必要があり、永続化済みのスキーマが代わりに読み込まれます。新規インデックスで省略した場合は空のスキーマが使用されます。 |
wal_sync_policy: | WalSyncPolicy | nil | nil | 先行書き込みログ(WAL)の耐久性ポリシー。nil の場合はデフォルトのレコードごと fsync を維持します。WAL 同期ポリシーと耐久性 を参照。 |
commit_policy: | CommitPolicy | nil | nil | 自動コミットポリシー。nil の場合はデフォルトの manual モード(呼び出し側がすべての commit を駆動)を維持します。コミットポリシーと自動コミット を参照。 |
ファイルベースインデックスの作成 vs 再オープン(path: を指定した場合): <path>/schema.toml がまだ存在しない場合、この呼び出しは新規インデックスを作成し、schema:(省略時は空のスキーマ)をそこに永続化します。<path>/schema.toml が既に存在する場合、この呼び出しは既存インデックスを再オープンします – schema: は省略しなければならず、指定すると ArgumentError が発生します(どちらのスキーマを優先すべきか曖昧になるため)。path: がこの規約導入以前のレイアウト(schema.toml が無く、セグメントファイルが path: 直下にある)のインデックスを含んでいる場合も ArgumentError になります。
メソッド
| メソッド | 説明 |
|---|---|
put_document(id, doc) | ドキュメントをアップサート(upsert)します。同じ ID の既存バージョンをすべて置換します。 |
add_document(id, doc) | 既存バージョンを削除せずにドキュメントチャンクを追記します。 |
put_documents(docs) | バッチ upsert。docs は [id, hash] ペアの Array で、バッチごとに WAL fsync 1 回で順に適用します(重複 ID はデデュープ、最後が勝ち)。最初の不正エントリで fail-fast し、適用済みの prefix はロールバックされません。 |
add_documents(docs) | バッチチャンク追記。put_documents と同様ですが、繰り返した ID は別バージョンとして蓄積されます。 |
get_documents(id) -> Array<Hash> | 指定 ID の全保存バージョンを返します。 |
delete_documents(id) | 指定 ID の全バージョンを削除します。 |
commit | バッファリングされた書き込みをフラッシュし、すべての保留中の変更を検索可能にします。 |
flush_wal | WAL の耐久バリアをオンデマンドで強制します。未同期の WAL レコードを同期的に fsync し、nil を返します。group-commit ポリシー下で実行する場合に有用です(下記参照)。 |
search(query, limit: 10, offset: 0, highlight: nil, rescore: nil) -> Array<SearchResult> | 検索クエリを実行します。rescore: には上位の結果を並べ替える LateInteractionRescore を渡します(Issue #1351)。それ以外の値は TypeError になります。LateInteractionRescore を参照。 |
search_batch(queries, limit: 10, offset: 0, highlight: nil) -> Array<Array<SearchResult>> | 独立した複数の検索を 1 回の呼び出しで実行します。各クエリは内部の tokio ランタイム上で並列に dispatch されます。results[i] は queries[i] に対応し、入力が空の配列の場合は [] を返します。highlight: はバッチ内のすべてのクエリに同一に適用されます。rescore: キーワードはありません。要素の SearchRequest は、その rescore: で再採点されます。 |
stats -> Hash | インデックス統計("document_count"、"vector_fields")を返します。 |
search の query 引数
query パラメータは以下のいずれかを受け付けます:
- DSL 文字列(例:
"title:hello"、"content:\"memory safety\"") - Lexical クエリオブジェクト(
TermQuery、PhraseQuery、BooleanQueryなど) - Vector クエリオブジェクト(
VectorQuery、VectorTextQuery) SearchRequest(完全な制御が必要な場合)
query が SearchRequest の場合は、その limit:・offset:・highlight:・rescore: が使われ、search のキーワード引数は無視されます。
search_batch の queries 配列の各要素も同じ種類の値を受け付けます。DSL 文字列・クエリオブジェクト・SearchRequest を 1 つのバッチ内で混在させることもできます。
ハイライト
search/search_batch の highlight: キーワード(Issue #1134)は、各ヒットの SearchResult#highlights にフィールドごとのハイライト済みフラグメントを要求します。以下のいずれかを受け付けます。
- フィールド名の配列:
highlight: ["body"] - Hash: 必須の
fieldsキー(String または Symbol)に加えて、HighlightConfigの任意の設定(max_fragments、fragment_size、tag、css_class、require_field_match、max_analyzed_chars、return_entire_field_if_no_highlight。キーは String・Symbol どちらも可)を指定 — 例:highlight: {fields: ["body"], tag: "em", max_fragments: 2}
results = index.search("body:rust", highlight: ["body"])
results[0].highlights # => {"body" => ["<mark>Rust</mark> is a systems programming language."]}
ハイライトは search/search_batch に渡したクエリ(または SearchRequest の query/lexical_query、下記参照)に従い、stored: true のテキストフィールドのみハイライト可能です。存在しない、保存されていない、テキスト型でないフィールドは黙ってスキップされます。highlight: を省略すると、すべての結果の highlights は空のままになります。同じ highlight: キーワードは SearchRequest.new でも使用できます。
WAL 同期ポリシーと耐久性
先行書き込みログ(WAL: Write-Ahead Log)は、コミット済みデータをクラッシュ
から保護します。デフォルトでは WAL は完全に耐久的で、すべてのレコードは
書き込みが返る前に fsync されます。group commit(グループコミット)
を有効にすると、fsync 呼び出しをまとめることで、耐久性をいくらか引き換えに
書き込みスループットを向上させられます。
WalSyncPolicy
Laurus::WalSyncPolicy は WAL のフラッシュ方法を記述するイミュータブルな
値オブジェクトです。Index.new(wal_sync_policy:) に渡します。
# デフォルト: 書き込みごとに耐久(各レコードを個別に fsync)。
Laurus::WalSyncPolicy.per_record
# Group commit: fsync をまとめてコストを償却。
Laurus::WalSyncPolicy.group(
max_records: nil, # このレコード数でフラッシュ(デフォルト 1024)
max_bytes: nil, # このバイト数でフラッシュ(デフォルト 1 MiB)
max_interval_ms: nil, # このミリ秒ごとに定期的にもフラッシュ
)
| コンストラクタ | 説明 |
|---|---|
WalSyncPolicy.per_record | デフォルト。すべてのレコードは書き込みが返る前に fsync されます。書き込みごとに完全に耐久的です。 |
WalSyncPolicy.group(max_records:, max_bytes:, max_interval_ms:) | fsync をまとめます。引数なしの場合はデフォルト(max_records: 1024、max_bytes: 1 MiB、タイマーなし)を使用します。WAL は max_records または max_bytes のいずれかが蓄積したとき、および毎回の commit 時にフラッシュされます。max_interval_ms: を指定すると、定期タイマーでもフラッシュします。 |
Group commit は SQLite の synchronous = NORMAL に相当します。クラッシュ時に
失われるのは最後の未同期バッチのレコードまでで、インデックスが破損する
ことはありません。レコードは常に commit 時に耐久化されるため、成功した
commit はポリシーに関わらず耐久バリアとなります。
フラッシュの強制
コミットの合間に耐久バリアを強制するには flush_wal を呼び出します。
例えば、バッチが安全に永続化されたことを通知する前などです。未同期の
レコードを同期的に fsync し、nil を返します。デフォルトのレコードごと
ポリシーでは実質的に no-op です。
# group commit を有効にし、必要に応じて耐久性を強制する。
policy = Laurus::WalSyncPolicy.group(max_records: 4096, max_bytes: 4 * 1024 * 1024)
index = Laurus::Index.new(path: "./myindex", wal_sync_policy: policy)
index.put_document("doc1", { "title" => "Hello" })
index.flush_wal # group バッチが満杯でなくてもレコードが永続化される
コミットポリシーと自動コミット
デフォルトでは、すべてのコミットは呼び出し側が駆動します。バッファリング
された書き込みは、明示的に commit を呼び出したときにのみ検索可能になり
ます。自動コミットポリシー(auto-commit policy) を使うと、その責務を
エンジンに委ねられ、一定数のドキュメントを適用するたび、または定期タイマー
で自動的にコミットされます。
CommitPolicy
Laurus::CommitPolicy は、エンジンがバッファリングされた書き込みをいつ
ストアへ実体化するかを記述するイミュータブルな値オブジェクトです。
Index.new(commit_policy:) に渡します。
# デフォルト: manual — すべてのコミットは呼び出し側が駆動。
Laurus::CommitPolicy.manual
# 自動コミット: N ドキュメント適用ごとにコミット。
Laurus::CommitPolicy.every_docs(1000)
# 自動コミット: 少なくとも N ミリ秒ごとにコミット(ネイティブのみ)。
Laurus::CommitPolicy.interval_ms(5000)
| コンストラクタ | 説明 |
|---|---|
CommitPolicy.manual | デフォルト。自動コミットなし。すべての commit は呼び出し側が駆動します。 |
CommitPolicy.every_docs(n) | n ドキュメント適用ごとに自動コミットします。単発・バッチ両方の取り込みを通してカウントされ、単一バッチ 内 でも n ドキュメントごとにコミットされます。 |
CommitPolicy.interval_ms(ms) | バックグラウンドタイマーで少なくとも ms ミリ秒ごとに自動コミットします。取り込みがアイドル状態でも、末尾の部分バッチがコミットされます。every_docs の時間ベース版です。デフォルト: なし。ネイティブのみ — WebAssembly(wasm32)ではバックグラウンドスレッドが存在しないため、エンジンはこれを no-op として扱います(値は構築されますが、タイマーによるコミットは発生しません)。 |
every_docs(0) は有効で、自動コミットを無効化します(manual と等価)。
コミットポリシーは WalSyncPolicy と直交して
います。WalSyncPolicy が WAL の fsync 耐久性を制御するのに対し、
CommitPolicy はストアがバッファリングされた書き込みをいつ実体化するかを
制御します。両者は独立して設定します。
# 1000 ドキュメント適用ごとに自動コミット。
policy = Laurus::CommitPolicy.every_docs(1000)
index = Laurus::Index.new(path: "./myindex", commit_policy: policy)
Schema
Index のフィールドとインデックスタイプを定義します。
Laurus::Schema.new
フィールドメソッド
| メソッド | 説明 |
|---|---|
add_text_field(name, stored: true, indexed: true, term_vectors: true, doc_values: true, analyzer: nil, multi_valued: false, position_increment_gap: 100) | 全文フィールド(転置インデックス、BM25)。term_vectors: はタームの位置を保存するかどうかを制御し、フレーズクエリ・スパンクエリが読み取ります。doc_values: は値を DocValues(ソート・ファセット・集計が読み取る列指向ストア)にもコピーするかどうかを制御します(Issue #1047)。stored: true の場合のみ有効です。multi_valued: true で String の Array を受け付けます(Issue #1175): term クエリはいずれかの要素がタームを含めばマッチし、フレーズクエリは slop が position_increment_gap:(デフォルト 100。0 にすると要素を連結したものとして付番)に達しない限り 2 つの要素をまたぎません。値は String の Array として読み戻されます。analyzer: にはパラメータ不要の組込名("standard" / "english" / "keyword" / "simple" / "noop"、または add_analyzer で登録したカスタム名)を指定します。Lindera 辞書パスが必要な Japanese プリセットは、lindera tokenizer を含むカスタム analyzer として登録し、名前で参照してください。 |
add_integer_field(name, stored: true, indexed: true, multi_valued: false, doc_values: true) | 64 ビット整数フィールド。multi_valued: true で整数配列を受け付け(範囲クエリは “any match”)。doc_values: は上記を参照。 |
add_float_field(name, stored: true, indexed: true, multi_valued: false, doc_values: true) | 64 ビット浮動小数点フィールド。multi_valued: true で浮動小数点配列を受け付け(範囲クエリは “any match”)。doc_values: は上記を参照。 |
add_boolean_field(name, stored: true, indexed: true, multi_valued: false, doc_values: true) | ブールフィールド。multi_valued: true で true / false の Array を受け付け(flags:true のような term クエリはいずれかの要素が値と等しければマッチ。値は true / false の Array として読み戻されます)。doc_values: は上記を参照。 |
add_bytes_field(name, stored: true, multi_valued: false) | 生バイトフィールド。doc_values: オプションはありません —— Bytes の値は設定にかかわらず DocValues に一切書き込まれないためです。multi_valued: true を渡すと base64 String の Array を受け付け(Issue #1176)、単一の base64 String と同じ方法で要素ごとにデコードされます。Bytes はそもそもインデックスされないため、他の multi_valued: オプションと異なりクエリ一致の意味論はなく、保存時の形と取り込み時の許容個数を変えるだけです。値はスカラーフィールドと同様、(バイナリ)String の Array として読み戻されます。 |
add_geo_field(name, stored: true, indexed: true, multi_valued: false, doc_values: true) | 地理座標フィールド(緯度/経度)。multi_valued: true で { "lat" => .., "lon" => .. } Hash の Array を受け付け(距離 / バウンディングボックスクエリはいずれかのポイントが条件を満たせばマッチ)。doc_values: は上記を参照。 |
add_geo3d_field(name, stored: true, indexed: true, multi_valued: false, doc_values: true) | 3D ECEF カルテシアン座標フィールド(x, y, z はメートル)。multi_valued: true で { "x" => .., "y" => .., "z" => .. } Hash の Array を受け付け(距離 / バウンディングボックス / nearest クエリはいずれかのポイントが条件を満たせばマッチ)。詳細は Geo3d の概念。doc_values: は上記を参照。 |
add_datetime_field(name, stored: true, indexed: true, multi_valued: false, doc_values: true) | UTC 日時フィールド。multi_valued: true で Time / DateTime / RFC 3339 String の Array を受け付け(範囲クエリはいずれかの時刻が条件を満たせばマッチ。値は UTC の RFC 3339 String の Array として読み戻されます)。doc_values: は上記を参照。 |
add_hnsw_field(name, dimension, distance: "cosine", m: 16, ef_construction: 200, quantizer: nil, subvector_count: nil, rerank_storage: nil, embedder: nil, pq_codebook_path: nil, base_weight: 1.0) | HNSW 近似最近傍ベクトルフィールド。base_weight は他の vector フィールドと同時に検索されたときの相対的なスコアリング優先度(Issue #1084)。ウェイトを参照。 |
add_flat_field(name, dimension, distance: "cosine", embedder: nil, base_weight: 1.0) | Flat(総当たり)ベクトルフィールド。 |
add_ivf_field(name, dimension, distance: "cosine", n_clusters: 100, n_probe: 1, embedder: nil, base_weight: 1.0) | IVF 近似最近傍ベクトルフィールド。 |
add_multi_vector_field(name, dimension, distance: "cosine", storage: "f32", embedder: nil) | 文書ごとに可変個のトークンベクトル(ColBERT のトークンごとの埋め込みなど)を保持する MultiVector フィールド(Issue #1351)。値は数値の Array の Array で、トークンごとに要素数 dimension の Array を 1 つ持ちます。ANN 索引は持たず、late interaction による再採点だけが読み取ります(LateInteractionRescore を参照)。トークンベクトルは保存されないため、get_documents や検索結果にこのフィールドは含まれません。distance: は "cosine" か "dot_product"、dimension は 0 より大きい値でなければならず、どちらもフィールド追加時に検査されます(ArgumentError)。storage: は各トークンベクトルのディスク上の要素種別を指定します — "f32"(デフォルト、正確)、"f16"(2倍小さい)、"int8"(約4倍小さいが非可逆圧縮)のいずれかで、こちらもフィールド追加時に検査されます(ArgumentError)。embedder: にはトークン単位のエンベダー("candle_colbert" のもの。エンベダータイプを参照)の名前を指定し、テキストの値と再採点のクエリテキストを埋め込みます。MultiVector フィールドを参照。 |
ベクトル量子化とリランクストレージ(HNSW フィールド):
quantizer—"scalar_8bit"(デフォルト、4 倍圧縮)または高圧縮率の"product_quantization"。Product quantization ではsubvector_count(dimensionを割り切れる値)が必須です。rerank_storage—"f32"を指定すると完全精度の*.hnsw.f32サイドカーを書き出し、厳密な Stage-2 リランクを有効化します。省略すると int8 のみのセグメントを維持します。pq_codebook_path— 共有 PQ codebook のストレージ相対ファイル名(Issue #631)。laurus train pq-codebookCLI コマンドで一度だけ学習します。quantizer: "product_quantization"との組み合わせでのみ意味を持ち、以後の commit は segment ごとの k-means 再学習の代わりに学習済み codebook で encode します。省略すると segment ごとの学習を維持します。
上記のどの add_*_field メソッドも、name が _(_id を除く)で始まる場合は ArgumentError を発生させ、何も追加しない。from_toml / from_toml_file で読み込むスキーマはそのようなフィールドを引き続き受け付けるため、永続化済みのスキーマはそのまま読み込める。ただし、そのスキーマから新しい Index を作成すると ArgumentError になる。詳細はフィールド命名規則を参照。
その他のメソッド
| メソッド | 説明 |
|---|---|
add_embedder(name, config) | 名前付きエンベダー定義を登録します。config は "type" キーを持つ Hash で、キーは String / Symbol どちらでも構いません(下記参照)。type が無い・未知である、または必須キーが無い場合は ArgumentError(invalid embedder config: ...)になります。 |
add_analyzer(name, tokenizer, char_filters: nil, token_filters: nil) | カスタムアナライザ定義を登録します。tokenizer は必須、char_filters:/token_filters: は省略可能な Hash の配列です。各 Hash はスキーマ TOML/JSON 形式と同じ {type: "..."} 形式で、キーは String / Symbol どちらでも構いません(下記参照)。組み込みアナライザ用に予約された名前(standard、keyword、english、simple、noop)は ArgumentError になり、その名前を定義したスキーマ(from_toml で読み込んだものなど)から新しい Index を作る場合も同じです。正規表現の妥当性など意味的な検証は、このメソッド呼び出し時点ではなく Index 構築時に行われます。 |
analyzer_names -> Array<String> | add_analyzer で登録された、または TOML から読み込まれたカスタムアナライザの名前一覧を返します。 |
Laurus::Schema.from_toml(toml_str) -> Schema (クラスメソッド) | laurus-cli create index --schema と同じ形式の TOML 文字列からスキーマを読み込みます。 |
Laurus::Schema.from_toml_file(path) -> Schema (クラスメソッド) | TOML ファイルからスキーマを読み込みます。 |
to_toml -> String | このスキーマを laurus-cli と同じ形式の TOML 文字列にシリアライズします。 |
to_toml_file(path) | このスキーマを TOML ファイルに書き込みます。 |
set_default_fields(fields) | クエリでフィールドが指定されていない場合に使用するデフォルトフィールドを設定します。fields は文字列の配列です。 |
set_dynamic_field_policy(policy) | 未宣言フィールドの扱いを設定します。policy は "strict" / "dynamic"(デフォルト)/ "ignore"。詳細は下記を参照。 |
dynamic_field_policy -> String | 現在のポリシーを小文字の文字列で返します。 |
field_names -> Array<String> | このスキーマに定義されたフィールド名のリストを返します。 |
Dynamic field policy(動的フィールドポリシー)
ドキュメントに含まれるがスキーマに宣言されていないフィールドの扱いを制御します:
"strict"— ドキュメントを拒否"dynamic"(デフォルト)— 各未宣言フィールドの型を推論してスキーマに追加。警告: integer フィールドに入ってきた float 値は静かに切り捨てられます(3.14→3)。厳密さが必要なら"strict"を使用してください"ignore"— 未宣言フィールドを静かに破棄
詳細な挙動マトリクスは スキーマとフィールド を参照してください。
エンベダータイプ
各型の説明を含む正規のリファレンスは スキーマフォーマットリファレンス → エンベダー を参照してください。
"type" | 必須キー | Feature Flag |
|---|---|---|
"precomputed" | – | (常に利用可能) |
"candle_bert" | "model" | embeddings-candle |
"candle_clip" | "model" | embeddings-multimodal |
"openai" | "model" | embeddings-openai |
"candle_colbert" | "model" | embeddings-candle |
"candle_colbert" は、省略可能なキー "revision"、"query_maxlen"、"doc_maxlen" も受け付けます。トークンベクトルを生成するため、使えるのは MultiVector フィールド(add_multi_vector_field)だけです。キーは String / Symbol どちらでも構いません。
schema = Laurus::Schema.new
schema.add_embedder(
"colbert",
{ type: "candle_colbert", model: "colbert-ir/colbertv2.0", query_maxlen: 32 },
)
schema.add_multi_vector_field("body_colbert", 128, embedder: "colbert")
アナライザコンポーネント
add_analyzer(name, tokenizer, char_filters: nil, token_filters: nil) と
[analyzers.<name>] TOML セクションで使用します。tokenizer は単一の Hash、
char_filters:/token_filters: は Hash の配列で、配列の順序どおりに適用されます。
各コンポーネントの説明を含む正規のリファレンスは スキーマフォーマットリファレンス → アナライザ を参照してください。
トークナイザ(tokenizer、必ず1つ):
type | 必須キー | 省略可能キー |
|---|---|---|
"whitespace" | – | – |
"unicode_word" | – | – |
"regex" | – | pattern(デフォルト \w+)、gaps(デフォルト false) |
"ngram" | min_gram、max_gram | – |
"lindera" | mode、dict | user_dict |
"whole" | – | – |
文字フィルタ(char_filters、トークン化前の生テキストに適用):
type | 必須キー | 省略可能キー |
|---|---|---|
"unicode_normalization" | form("nfc"/"nfd"/"nfkc"/"nfkd") | – |
"pattern_replace" | pattern、replacement | – |
"mapping" | mapping(置換用の Hash) | – |
"japanese_iteration_mark" | – | kanji(デフォルト true)、kana(デフォルト true) |
トークンフィルタ(token_filters、トークン化後のトークン列に適用):
type | 必須キー | 省略可能キー |
|---|---|---|
"lowercase" | – | – |
"stop" | – | words(デフォルト: 英語のストップワード) |
"stem" | – | stem_type("porter"/"simple"/"identity") |
"boost" | boost | – |
"limit" | limit | – |
"strip" | – | – |
"remove_empty" | – | – |
"flatten_graph" | – | – |
schema = Laurus::Schema.new
schema.add_analyzer(
"ja_ipadic",
{ type: "lindera", mode: "normal", dict: "/var/lib/lindera/ipadic" },
char_filters: [
{ type: "unicode_normalization", form: "nfkc" },
{ type: "japanese_iteration_mark" },
],
token_filters: [{ type: "lowercase" }],
)
schema.add_text_field("title", analyzer: "ja_ipadic")
距離メトリクス
| 値 | 説明 |
|---|---|
"cosine" | コサイン類似度(デフォルト) |
"euclidean" | ユークリッド距離 |
"dot_product" | 内積 |
"manhattan" | マンハッタン距離 |
"angular" | 角度距離 |
クエリクラス
TermQuery
Laurus::TermQuery.new(field, term)
指定フィールドに完全一致する語句を含むドキュメントを検索します。
PhraseQuery
Laurus::PhraseQuery.new(field, terms)
指定した語句が順序どおりに含まれるドキュメントを検索します。terms は文字列の配列です。
FuzzyQuery
Laurus::FuzzyQuery.new(field, term, max_edits: 2)
編集距離が max_edits 以内の近似一致を検索します。
WildcardQuery
Laurus::WildcardQuery.new(field, pattern)
ワイルドカードパターン検索。* は任意の文字列、? は任意の1文字に一致します。
NumericRangeQuery
Laurus::NumericRangeQuery.new(field, min: nil, max: nil)
[min, max] の範囲内の数値を検索します。開いた境界には nil を指定します。型(整数または浮動小数点)は min/max の Ruby 型から推論されます。
DateTimeRangeQuery
Laurus::DateTimeRangeQuery.new(field, min: nil, max: nil)
[min, max] の範囲内(両端を含む)の DateTime 値を検索します。開いた境界には nil を指定する(またはキーワードを省略する)と開放されます。境界は Query DSL が受け付ける任意の形式の String リテラル(RFC 3339 の "2024-01-01T09:00:00+09:00"(UTC に正規化)、オフセットなしの "YYYY-MM-DDTHH:MM:SS[.fff]"(UTC)、"YYYY-MM-DD"(その日の 0 時 UTC))、または iso8601 に応答する任意のオブジェクト(Time、DateTime)です。不正な境界は構築時に ArgumentError を発生させます。クエリオブジェクトを受け付ける場所(Index#search、BooleanQuery、SearchRequest)ならどこでも使用できます。
GeoDistanceQuery
Laurus::GeoDistanceQuery.within_radius(field, lat, lon, distance_m)
地理的距離検索(半径指定)。指定した地点から distance_m メートル以内の
(lat, lon) 座標を持つドキュメントを返します。
GeoBoundingBoxQuery
Laurus::GeoBoundingBoxQuery.within_bounding_box(
field, min_lat, min_lon, max_lat, max_lon,
)
地理的範囲(バウンディングボックス)検索。軸並行 [min_lat, max_lat] × [min_lon, max_lon] 内の (lat, lon) 座標を持つドキュメントを返します。
Geo3dDistanceQuery
Laurus::Geo3dDistanceQuery.within_sphere(field, x, y, z, distance_m)
3D ECEF 座標フィールドへの球距離検索。中心 (x, y, z) から distance_m メートル以内
の座標を持つドキュメントを返します。ECEF の理論については
Geo3d の概念 を参照。
Geo3dBoundingBoxQuery
Laurus::Geo3dBoundingBoxQuery.within_box(
field,
min_x, min_y, min_z,
max_x, max_y, max_z,
)
軸並行 3D 範囲(AABB)検索。
Geo3dNearestQuery
Laurus::Geo3dNearestQuery.k_nearest(
field, x, y, z, k,
initial_radius_m: nil,
max_radius_m: nil,
)
3D ECEF 座標フィールドへの k 最近傍検索。initial_radius_m: / max_radius_m:
キーワード引数(オプション)で反復拡張サーチの探索コーンを調整できます。
BooleanQuery
bq = Laurus::BooleanQuery.new
bq.must(query)
bq.should(query)
bq.must_not(query)
複合ブールクエリ。must 節はすべて一致する必要があり、must_not 節は一致してはなりません。should 節はスコアリングに寄与し、must 節が無い場合は少なくとも1つが一致する必要があります。
SpanQuery
# 単一語句
Laurus::SpanQuery.term(field, term)
# Near: slop 位置以内の語句
Laurus::SpanQuery.near(field, terms, slop: 0, ordered: true)
# ネストされた SpanQuery 句を使った Near
Laurus::SpanQuery.near_spans(field, clauses, slop: 0, ordered: true)
# Containing: big スパンが little スパンを含む
Laurus::SpanQuery.containing(field, big, little)
# Within: 最大距離での include スパンと exclude スパン
Laurus::SpanQuery.within(field, include_span, exclude_span, distance)
位置・近接スパンクエリ。near は語句文字列の配列を受け取り、near_spans はネスト式のために SpanQuery オブジェクトの配列を受け取ります。
VectorQuery
Laurus::VectorQuery.new(field, vector)
事前計算済みエンベディングベクトルを使った近似最近傍検索を行います。vector は Float の配列です。
VectorTextQuery
Laurus::VectorTextQuery.new(field, text)
クエリ時に text をエンベディングに変換してベクトル検索を行います。インデックスにエンベダーの設定が必要です。
SearchRequest
高度な制御が必要な場合の完全なリクエストクラスです。
Laurus::SearchRequest.new(
query: nil,
lexical_query: nil,
vector_query: nil,
filter_query: nil,
fusion: nil,
limit: 10,
offset: 0,
highlight: nil,
rescore: nil,
)
| パラメータ | 説明 |
|---|---|
query: | DSL 文字列または単一クエリオブジェクト。lexical_query: / vector_query: と排他的。 |
lexical_query: | 明示的なハイブリッド検索の Lexical コンポーネント。 |
vector_query: | 明示的なハイブリッド検索の Vector コンポーネント。 |
filter_query: | スコアリング後に適用する Lexical フィルター。 |
fusion: | フュージョンアルゴリズム(RRF または WeightedSum)。両コンポーネント指定時のデフォルトは RRF(k: 60)。 |
limit: | 最大結果件数(デフォルト 10)。 |
offset: | ページネーションオフセット(デフォルト 0)。 |
highlight: | Index#search の highlight: と同じ配列または Hash の形式(Issue #1134)。ハイライトを参照。 |
rescore: | リクエスト(lexical・vector・ハイブリッドのいずれも可)の上位の結果を並べ替える LateInteractionRescore(Issue #1351)。それ以外の値は TypeError になります。LateInteractionRescore を参照。 |
LateInteractionRescore
検索結果の上位を late interaction(ColBERT の MaxSim)で再採点します(Issue #1351)。Index#search または SearchRequest.new の rescore: に渡します。
Laurus::LateInteractionRescore.new(field, query, window_size: nil)
| パラメータ | 型 | デフォルト | 説明 |
|---|---|---|---|
field | String | – | MultiVector フィールド(add_multi_vector_field)。 |
query | String | Array<Array<Numeric>> | – | クエリテキスト(フィールドのトークン単位のエンベダー、つまり "candle_colbert" のものが埋め込みます)、またはクエリのトークンベクトル(文書のトークンベクトルと同じモデルで計算したもの)。要素には Integer も使えます。 |
window_size: | Integer | nil | nil(100) | 再採点する 1 段目の上位結果の件数。最大 10,000。nil のときは既定値の 100 になります。 |
| メソッド | 説明 |
|---|---|
window_size -> Integer | 再採点する上位結果の件数を返します。 |
inspect -> String | LateInteractionRescore(field="tokens", window_size=100) のような要約を返します。 |
1 段目の上位 window_size 件の結果を、フィールドに対する MaxSim で並べ替えます。再採点された結果の score はその MaxSim です。ウィンドウ外の結果は 1 段目の順序とスコアのまま、再採点された結果の後に続きます。順序の規則と類似度の詳細は ベクトル検索 → late interaction による再採点 を参照してください。
エラー: query が String でも数値の Array の Array でもない場合、コンストラクタが TypeError を発生させます。それ以外の値は検索時にエンジンが検査し、フィールドが存在しない・MultiVector フィールドでない、テキストクエリが空・フィールドにトークン単位のエンベダーが無い、クエリがフィールドの次元のトークンベクトルを 1〜1,024 個持たない、window_size が 1〜10,000 の範囲外、のいずれかの場合に、メッセージに rescore: ... を含む ArgumentError を発生させます。
schema = Laurus::Schema.new
schema.add_text_field("title")
schema.add_multi_vector_field("tokens", 2, distance: "dot_product")
index = Laurus::Index.new(schema: schema)
index.put_document("a", { "title" => "rust", "tokens" => [[0.1, 0.0]] })
index.put_document("b", { "title" => "rust language", "tokens" => [[0.9, 0.2]] })
index.commit
rescore = Laurus::LateInteractionRescore.new("tokens", [[1.0, 0.0], [0.0, 1.0]], window_size: 50)
results = index.search("title:rust", rescore: rescore)
results.map(&:id) # => ["b", "a"] -- "b" の MaxSim は 1.1、"a" は 0.1
# フィールドに "candle_colbert" のエンベダーがあれば、クエリをテキストで渡せる。
rescore = Laurus::LateInteractionRescore.new("body_colbert", "how do lifetimes work")
SearchResult
Index#search が返すクラスです。
result.id # => String -- 外部ドキュメント識別子
result.score # => Float -- 関連性スコア
result.document # => Hash|nil -- 取得されたフィールド値。削除済みの場合は nil
result.highlights # => Hash -- 要求したフィールドごとのハイライト済みフラグメント
highlights は highlight: で指定した各フィールドをハイライト済みフラグメント(最も良いものが先頭)にマッピングします。ハイライトされなかったフィールドは Hash に現れず、highlight: を要求しなかった場合 highlights は {} になります。詳細はハイライトを参照してください。
フュージョンアルゴリズム
RRF
Laurus::RRF.new(k: 60.0)
逆順位フュージョン(Reciprocal Rank Fusion)。Lexical と Vector の結果リストを順位位置によってマージします。k は平滑化定数で、値が大きいほど上位ランクの影響が小さくなります。
WeightedSum
Laurus::WeightedSum.new(lexical_weight: 0.5, vector_weight: 0.5)
両スコアリストをそれぞれ正規化した後、lexical_weight * lexical_score + vector_weight * vector_score として結合します。
テキスト解析
SynonymDictionary
dict = Laurus::SynonymDictionary.new
dict.add_synonym_group(["fast", "quick", "rapid"])
同義語グループの辞書です。グループ内のすべての語句は互いの同義語として扱われます。
WhitespaceTokenizer
tokenizer = Laurus::WhitespaceTokenizer.new
tokens = tokenizer.tokenize("hello world")
空白で分割してテキストをトークン化し、Token オブジェクトの配列を返します。
SynonymGraphFilter
filter = Laurus::SynonymGraphFilter.new(dictionary, keep_original: true, boost: 1.0)
expanded = filter.apply(tokens)
SynonymDictionary の同義語でトークンを展開するトークンフィルターです。
Token
token.text # => String -- トークンテキスト
token.position # => Integer -- トークンストリーム内の位置
token.start_offset # => Integer -- 元テキスト内の UTF-8 バイト開始オフセット
token.end_offset # => Integer -- 元テキスト内の UTF-8 バイト終了オフセット
token.boost # => Float -- スコアブースト係数(1.0 = 調整なし)
token.stopped # => Boolean -- ストップフィルターによって除去されたかどうか
token.position_increment # => Integer -- 前のトークンの位置との差分
token.position_length # => Integer -- このトークンがカバーする位置数
token.token_type # => String または nil -- トークン種別(例: "alphanum")
オフセットは文字数ではなくバイト数です。非 ASCII のテキストではバイト単位で切り出します: text.byteslice(token.start_offset...token.end_offset)。
token_type は "alphanum"、"num"、"cjk"、"katakana"、"hiragana"、"hangul"、"punctuation"、"whitespace"、"synonym"、"email"、"url"、"other" のいずれか、または nil です。SynonymGraphFilter#apply は各トークンのオフセットと種別を保ち、挿入する同義語には種別 "synonym" と、置き換える語のオフセットを付けます。
フィールド値の型マッピング
Ruby の値は自動的に Laurus の DataValue 型に変換されます:
| Ruby 型 | Laurus 型 | 備考 |
|---|---|---|
nil | Null | |
true / false | Bool | |
Integer | Int64 | |
Float | Float64 | |
String | Text | |
Array(Integer) | Int64Array | 多値整数フィールド。ベクトルフィールドでは配列を f32 にキャスト。空の Array は空の Int64Array |
Array(数値) | Float64Array | 多値浮動小数点フィールド(整数は拡張)。ベクトルフィールドでは配列を f32 にキャスト |
Array(数値の Array の配列) | VectorArray | MultiVector フィールド(add_multi_vector_field)のトークンベクトル。トークンごとにフィールドの次元の Array を 1 つ持つ(Issue #1351)。Integer の要素も可。true や String などそれ以外の要素は TypeError。get_documents や検索結果には返されない |
Hash("lat", "lon") | Geo | 2 つの Float 値 |
Hash("x", "y", "z") | GeoEcef | 3 つの Float 値(メートル単位、3D ECEF 直交座標) |
Array("lat", "lon" を持つ Hash の配列) | GeoArray | フィールドに multi_valued: true が必要 |
Array("x", "y", "z" を持つ Hash の配列) | GeoEcefArray | フィールドに multi_valued: true が必要 |
Time / String(iso8601 に応答) | DateTime | iso8601 経由で変換 |
Array(Time、または iso8601 に応答する他のオブジェクトを含む) | DateTimeArray | 各要素を RFC 3339 としてパース(iso8601 に応答するオブジェクトは先に変換)。日時でない要素は ArgumentError。フィールドに multi_valued: true が必要 |
Array(String) | DateTimeArray または TextArray | 全要素が RFC 3339 としてパースできれば DateTimeArray、そうでなければ TextArray(Issue #1175。String の Array として読み戻される)。フィールドに multi_valued: true が必要。宣言済みの多値 Bytes フィールドでは、同じ base64 String の Array が要素ごとにデコードされる(Issue #1176) |
Array(true / false) | BoolArray | 全要素が true または false であること。[true, 1] のような混在 Array は TypeError。フィールドに multi_valued: true が必要 |