インデックスは、データベースクエリを高速化するための重要なツールです。パフォーマンス専有型のセカンダリインデックスに加えて、Lindorm は SearchIndex もサポートしています。SearchIndex は、複雑で多次元なクエリシナリオ向けに設計されており、あいまいクエリ、集約と分析、ソート、ページングを処理できます。このトピックでは、SearchIndex の技術的な仕組みとコア機能について説明します。
背景情報
大規模なデータストレージ、クラウドネイティブ技術、そして 5G/IoT 時代の到来に伴い、新しいビジネスモデルが次々と生まれています。単純なプライマリキーや範囲クエリを超えて、基本的な分析や多次元検索は、基本的なビジネス要件となっています。一般的なクエリ要件には、以下のようなものがあります。
多次元クエリ:通常、列のランダムな組み合わせを含むアドホッククエリ。
カウント操作:テーブルの総行数、またはクエリに一致する行数を取得します。
指定列によるソート:特定の列に基づいて結果を昇順または降順にソートします。例えば、注文を時間で降順にソートするなどです。
トークン化と検索:テキストフィールドに対してトークンベースの検索を実行し、関連性の高い結果を返します。
統計集約:特定のフィールドでデータをグループ化および集約し、合計、最大値、最小値、平均値を計算したり、重複排除された結果セットを返したりします。
あいまいクエリ:「Alibaba Cloud」のような結果に一致するように、「Ali」で始まるデータを検索します。これは MySQL の LIKE 構文に似ています。
大量データの低コストストレージと多様な検索に対する需要は、ますます多くのビジネスにとって基本的な要件となっています。Lindorm は、高いスケーラビリティと低コストという本来の利点を活かしながら、これらの多様なクエリシナリオをどのようにサポートするかを探求し続けています。
Lindorm SearchIndex の設計思想
限られたリソースで大量のデータセットに対する複雑なクエリを効率的に処理するために、Lindorm はネイティブなデータベース機能として機能する新しいエンジンを設計しました。インデックスは通常、クエリを高速化するために使用されます。新しいインデックスタイプを追加することで、Lindorm は大量データの複雑なクエリ問題を解決できます。マルチモーダルデータベースとして、Lindorm は検索エンジンをネイティブにサポートし、フルテキストインデックス作成機能を内蔵しています。この検索エンジンを Lindorm のワイドテーブルモデルと統合することで、SearchIndex が誕生しました。これにより、基盤となるエンジンやデータフローを管理することなく、新しいインデックスを作成するだけで複雑なクエリ問題を解決できます。その体験は、Lindorm のセカンダリインデックスを使用するのと同じくらい便利です。SearchIndex は、以下のコア機能の構築に重点を置いています。
統一されたメタデータ
複数のシステムにまたがる複雑な運用保守 (O&M) の根本原因は、メタデータの不整合です。各システムは、それぞれ固有のコマンドを必要とします。例えば、あるシステムでテーブルを作成した後、別のシステムでもインデックスを作成する必要があります。Lindorm は、統一された分散メタデータを維持することで、エンジン間のスキーマの違いを抽象化し、DDL 操作に統一されたコマンドを提供します。
統一されたインターフェイス
システムが異なればインターフェイスも異なります。独自の統一されたインターフェイスを実装すると、開発の複雑さは軽減されますが、開発者は新しいインターフェイスを学習する必要があり、アプリケーション開発コストを大幅に下げることにはなりません。SQL は多くのデータベースシステムの標準開発言語であり、学習曲線が緩やかです。Lindorm SearchIndex は、SQL ライクなインターフェイスである CQL をネイティブにサポートしています。開発中、インデックスの存在を意識する必要はありません。ユーザー体験は、標準のワイドテーブルにアクセスする場合と一貫しています。
強力な整合性
複数のエンジン間でデータが流れると、必然的に整合性の問題が発生します。通常、システムは結果整合性しか提供できず、これはデータの正確性とアクセス遅延を効果的に保証できないことを意味します。Lindorm SearchIndex は、結果整合性と強力な整合性の両方を提供します。アクセス量が多く、データ遅延に対する秘密度が低いシナリオでは、結果整合性が非常に高いスループットと可用性を提供します。アクセス遅延に敏感なアプリケーションには、強力な整合性モデルがより良い選択です。データが正常に書き込まれた後、インデックスはすぐに検索可能になります。
リソースの隔離
異種システムはリソース使用量のパターンが異なるため、リソース使用率を最大化するには効果的な隔離メカニズムが必要です。Lindorm は、
ストレージとインデックス作成の分離モデルを使用して、システムの堅牢性と弾力性を確保します。LindormTable エンジンは生データを非常に低コストで保存し、検索エンジンはインデックス作成と取得を処理します。2つのエンジンは、異なる CPU とメモリリソースで構成でき、独立してスケーリングできます。
Lindorm SearchIndex の機能分析
例
SearchIndex を使用してインデックステーブルを作成する場合、インデックスキー列名をリストするだけで済みます。クエリを実行する際にインデックステーブルを参照する必要はありません。以下の例は、Lindorm CQL を使用して SearchIndex を操作する方法を示しています。
CQL は Cassandra のクエリ言語です。Lindorm は Cassandra API とシームレスに互換性があります。
ソーステーブル
CREATE TABLE myTable ( id bigint, name text, age int, sex text, city text, address text, PRIMARY KEY (id) ) WITH compression = {'class': 'ZstdCompressor'};インデックス
name、age、sex、city、address 列にフルテキストインデックスを作成します。
CREATE SEARCH INDEX myIndex ON myTable WITH COLUMNS (name, age, sex, city, address);説明インデックスキー列の順序は関係ありません。(c3, c2, c1) のインデックスは (c1, c2, c3) のインデックスと同じ効果があります。
クエリ
標準クエリ文
あいまいクエリ: SELECT * FROM myTable WHERE name LIKE 'Xiao%' ソート付き多次元クエリ: SELECT * FROM myTable WHERE city='Hangzhou' AND age>=18 ORDER BY age ASC ページング付き多次元クエリ: SELECT * FROM myTable WHERE name='Xiao Liu' AND sex=false OFFSET 100 LIMIT 10 ORDER BY age DESC高度なクエリ文
ソート付き多次元クエリ: SELECT * FROM myTable WHERE search_query='+city:Hangzhou +age:[18 TO *] ORDER BY age ASC' テキスト取得: SELECT * FROM myTable WHERE search_query='address:Xihu District'
利用シーン
SearchIndex は、Alibaba 内の複数のビジネスシナリオで成功裏に使用されています。この機能は現在パブリッククラウドで利用可能であり、以下の主要な機能をサポートしています。
多次元クエリ:Term クエリ、範囲クエリ、および条件の任意の組み合わせを使用するその他のクエリ。
ワイルドカードクエリ:* を使用して任意の数の文字を表し、? を使用して任意の単一の文字を表します。
統計集約:最小値、最大値、合計、平均値を計算し、行数をカウントします。
ソートとページング:任意のインデックスキー列で出力をソートします。
テキストトークン化:中国語/英語のトークン化、デリミタトークン化、ピンイントークン化などをサポートします。
地理位置情報:距離クエリおよび矩形/多角形範囲クエリ。
これらの機能により、Lindorm をさまざまなビジネスシナリオに適用できます。一般的なユースケースは次のとおりです。
注文詳細:物流注文、取引請求書など。注文の多次元クエリとソートをサポートします。
ユーザーペルソナとタギング:例えば、企業は購入者を選択してタグ付けし、ターゲットを絞った情報を配信できます。
テキスト検索:例えば、ログ分析や異常情報の取得など。
仕組み
複数のモデルをサポートするマルチモーダルデータベースとして、Lindorm は検索エンジンとワイドテーブルモデルを深く統合し、直感的で使いやすい SearchIndex 機能を提供します。全体的な階層アーキテクチャは次のとおりです。
クエリアクセス
複数の QueryProcessor ノードで構成されるこのレイヤーは、クエリアクセス、SQL 解析、およびルールベース最適化 (RBO) に基づく適切なインデックスの自動選択を担当します。
インデックス前処理
このレイヤーは、新しく挿入または更新された生データを、インデックスキー列のメタデータに基づいてインデックスデータに変換します。さまざまなシナリオに応じて、適切な Mutability プロパティを選択できます。例えば、データが書き込まれた後に更新されない日次モニタリングでは、Immutable モードを使用して生インデックスデータを直接生成できます。部分的な更新が頻繁に必要なステートフルなデータの場合、既存データを読み取って完全な生インデックスデータを構築します。このレイヤーは、カスタムタイムスタンプを持つデータの書き込みもサポートし、データが正しい順序で処理されることを保証します。
インデックス同期
結果整合性モデル (デフォルト) の場合、Lindorm エコシステムのデータ同期サービスである Lindorm Tunnel Service (LTS) は、効率的なリアルタイム同期と完全移行機能を提供します。先行書き込みログ (WAL) の変更をリアルタイムで監視し、生インデックスデータを変換して検索エンジンに書き込むことができます。また、1回の読み取りで複数回の書き込みもサポートしており、1つの WAL を複数のインデックステーブルに同期できるため、同期効率が大幅に向上します。強力な整合性モデルの場合、生インデックスデータは構築後に検索エンジンに同期的に書き込まれます。その後、検索エンジンはリアルタイムでフルテキストインデックスを生成し、データが書き込まれた直後に検索可能になる強力な整合性を提供します。
インデックスエンジン
複数のノードで構成される分散 Lucene クラスター。データはハッシュまたは範囲によって複数のシャードにパーティション分割され、フルテキスト検索機能を提供します。
インデックスストレージ
インデックスデータは、分散ファイルシステム Lindorm DFS に保存されます。ストレージとコンピュートを分離するアーキテクチャは、優れたスケーラビリティを提供します。同時に、ストレージレイヤーでの透明な圧縮とインテリジェントなコールド・ホットデータ分離により、インデックスストレージコストを大幅に削減できます。
コア機能
オンライン DDL 操作
分散データベースとして、Lindorm は水平スケーリングにより、毎秒最大数億回の操作処理能力をサポートできます。インデックスの DDL 操作が DML をブロックすると、高並行性アプリケーションへの影響は増大します。Lindorm の分散メタデータ管理を使用することで、SearchIndex はデータ整合性を損なうことなくオンライン DDL 操作をサポートします。
インデックスキー列の動的な追加と削除
ワイドテーブルシナリオでは、特にインデックスキー列が頻繁に追加または削除されるユーザーペルソナシナリオでは、列が固定されない場合があります。SearchIndex は、インデックスキー列を動的に管理するための Java API と CQL インターフェイスを提供します。
インデックスキー列のプロパティをオンラインで変更
各インデックスキー列は、`indexed` (インデックスを作成するかどうか、デフォルトは true)、`stored` (元の値を保存するかどうか、デフォルトは false)、`docvalues` (フォワードインデックスを維持するかどうか、デフォルトは true)、トークン化タイプなど、複数のプロパティをサポートします。例えば、インデックスキー列が最初に `stored` として設定されていなかった場合、元の値はインデックステーブルに保存されません。サーバー側は自動的に Lindorm ワイドテーブルをクエリして生データを取得します。この場合、インターフェイスを使用して列の `stored` プロパティを true に変更できます。
圧縮の動的な変更
Lindorm では、ワイドテーブルの作成時に ZSTD や Snappy などの圧縮アルゴリズムを設定したり、作成後に動的に変更したりできます。SearchIndex は独立したインデックステーブルであり、Lucene に依存しています。Lucene は LZ4 と ZLIB 圧縮アルゴリズムしかサポートしていません。プライマリテーブルとインデックステーブルのプロパティの一貫性を確保するために、Lucene は ZSTD と Snappy 圧縮アルゴリズムをサポートするように変更されました。したがって、プライマリテーブルの圧縮アルゴリズムを変更すると、SearchIndex も更新されます。これにより、インデックスのストレージサイズが効果的に削減されます。
TTL の自動同期
インデックスの TTL 値は、ワイドテーブルの TTL 値と自動的に同期されます。ワイドテーブルに TTL が設定されている場合、インデックスは現在の TTL 値を継承します。ワイドテーブルに TTL が設定されていない場合、ワイドテーブルに初めて TTL が設定されると、インデックスの TTL は自動的に同期されます。インデックスの TTL を動的に変更することはできません。
インデックステーブルのステータスの動的な変更
インデックステーブルには、DISABLED (書き込みもクエリも不可)、BUILDING (書き込みは可能だがクエリは不可)、ACTIVE (書き込みもクエリも可能) の3つの主要なステータスがあります。インデックスを作成または削除したり、既存データにインデックスを構築したりする場合、インデックスのステータスを動的に変更する必要がよくあります。これは、実行中の DML リクエストに影響を与えてはなりません。
複数の整合性レベル
Lindorm ワイドテーブルと同様に、SearchIndex はさまざまなビジネスシナリオに対応するために、複数の整合性レベルをサポートするように設計されています。
整合性レベル | 読み取り/書き込み整合性の保証 | 可用性 |
結果整合性 (EC) | データ書き込み後、読み取り可能になるまでに短い遅延 (秒単位) があります。 | 読み取りと書き込みは、ハングやグリッチを回避できます。 障害からの読み取り/書き込みの回復には 10 ミリ秒かかります。 |
強力な整合性 (SC) | データ書き込み後、すぐに 100% 読み取り可能です。 | プライマリレプリカのみが読み取りと書き込みを処理します。 プライマリレプリカの障害からの回復は通常、秒単位です。 |
選択可能なインデックス構築コスト
インデックスはクエリを高速化し、ビジネスがデータからより多くの価値を引き出すのに役立ちますが、書き込みコストとストレージコストも増加させます。一方では、Lindorm は複数の効率的な圧縮アルゴリズムを使用してインデックスのストレージサイズを大幅に削減します。他方では、インデックス構築が書き込みスループットに与える影響を軽減するために、選択可能なインデックス構築方法を提供します。Index WAL building の速度は、生データの書き込みパフォーマンスに直接影響します。Lindorm ワイドテーブルは、部分的な列の更新をネイティブにサポートする Key-Value (KV) データベースです。しかし、Lucene 検索エンジンは行全体しか更新できず、部分的な更新をサポートしていません。したがって、インデックスを構築する際、Lindorm はプライマリテーブルを読み取って既存データを取得し、完全なインデックス WAL を構築する必要があります。Lindorm は、この読み取り操作をビジネスシナリオに基づいて分類し、さまざまなオプションを提供します。
構築方法 | シナリオ | プロパティ |
IMMUTABLE (最低コスト) | 追記専用シナリオ (データは TTL によって期限切れになる可能性があります)。 例えば、書き込み後に更新または削除されないモニタリングデータやログデータなど。 | インデックス構築は非常に効率的です。古いデータを読み戻す必要がなく、現在のデータに基づいて直接インデックスを生成します。 |
MUTABLE_LATEST (中コスト) | 一般的なシナリオ (ユーザー定義型 (UDT) を除く)。 | インデックスキー列が c1 と c2 であると仮定します。最初の書き込みは列 c1 に、2回目の書き込みは列 c2 に行われます。2回目に c2 の値が書き込まれるとき、完全なインデックスデータ (c1, c2) を構築するために c1 の元の値を読み取る必要があります。 |
MUTABLE_ALL (最高コスト) | ユーザー定義のタイムスタンプでデータを書き込む場合。 例えば、完全タスクと増分タスクが共存するシナリオでは、完全タスクは増分書き込みからのデータを上書きしないように、タイムスタンプを伴う必要があります。 |
|
効率的な同期
結果整合性モデルでは、インデックスデータの同期は LTS サービスに依存します。Lindorm エコシステムのデータトンネルとして、LTS は効率的なリアルタイム同期と完全移行機能を提供します。ワイドテーブルに書き込まれたデータはミリ秒以内に検出され、検索エンジンに迅速に同期されます。
同期の可視化
LTS の Web インターフェイスには、同期時間、インデックステーブル情報、同期されたデータ量など、インデックス同期に関する詳細情報が表示されます。LTS はこれらの詳細をモニタリングメトリックとしてエクスポートし、アラートシステムと統合して、同期リンクの健全性をリアルタイムでモニタリングすることもできます。
高効率な同期
LTS は、内部で高並行性のプロデューサー・コンシューマーモデルを使用して、大量のデータを迅速に処理します。単一の WAL は一度だけ読み取る必要があります。また、水平スケーリングもサポートしています。新しいノードは同期リンクに迅速に参加して、インデックスデータの同期を高速化できます。
WAL の順序保持
非表示のタイムスタンププロパティを使用して、書き込み順序が保持されます。ワイドテーブルに書き込まれたデータは、同じシーケンスで検索インデックスに書き込まれます。これにより、ワイドテーブルと検索インデックス間のデータ整合性が確保され、LilyIndexer に存在したデータ順序の乱れの問題が完全に解決されます。
高速なフルビルド
既存のデータについては、LTS の完全タスク実行メカニズムを使用して、ワイドテーブルから生データを効率的に取得し、インデックスを生成できます。テラバイト規模のデータセットは数分以内にインデックスを作成できます。
リアルタイム検索
書き込み操作が成功した直後にインデックス付きデータをクエリできる機能は、リアルタイム可視性として知られており、これは強力な整合性モデルです。SearchIndex は Lucene に根本的な依存関係があり、Lucene には大きな欠点があります。データは書き込まれた直後に検索可能にはなりません。データを検索可能にするには、明示的な Flush または Commit 操作を実行する必要があります。これにより、Lucene ベースのサービスはリアルタイムのビジネスシナリオには適さなくなります。これらは、モニタリングやロギングなど、リアルタイム要件がそれほど厳しくないシナリオにのみ適しています。業界では、Elasticsearch や Solr などの Lucene ベースの分散検索エンジンは、near-real-time (NRT) 検索機能を提供することでこの問題を軽減しています。この機能は、インデックス付きデータが特定の時間枠 (通常は数秒以内) に検索可能になることを保証しますが、それでも真のリアルタイム要件は満たしていません。
書き込まれたデータをすぐにクエリできないという問題に対処するため、Lindorm は Lucene ベースのソリューションを使用してリアルタイムのインデックス可視性を提供します。このソリューションは、詳細なデータ構造と動的なメモリ管理メカニズムを使用して、インデックスデータが書き込まれた直後にクエリ可能であることを保証し、リアルタイムのパフォーマンスを実現します。
CQL API
CQL は Cassandra の公式クエリ言語です。これは、NoSQL データベースの特性に適した SQL の方言です。Lindorm は Cassandra とシームレスに互換性があるため、CQL を使用して SearchIndex にアクセスすることがデフォルトで推奨されます。
DDL
インデックスの作成
CREATE SEARCH INDEX index_name [ IF NOT EXISTS ] ON [keyspace_name.]table_name | [ WITH [ COLUMNS (column1,...,columnn) ] | [ WITH [ COLUMNS (*) ]インデックスの削除
DROP SEARCH INDEX [IF EXISTS] ON [keyspace_name.]table_name;インデックスの再構築
REBUILD SEARCH INDEX [IF EXISTS] ON [keyspace_name.]table_name;インデックスの変更
ALTER SEARCH INDEX SCHEMA [IF EXISTS] ON [keyspace_name.]table_name ( ADD column_name | DROP column_name) ;
DML
標準クエリ。`WHERE` 句の後に特定の条件が続きます。
search_query クエリ
SELECT selectors FROM table WHERE (indexed_column_expression | search_query = 'search_expression') [ LIMIT n ] [ ORDER BY column_name ]
標準のクエリ構文が取得ニーズに不十分な場合は、search_query を使用して Lucene 構文で検索エンジンから直接データを取得できます。例えば、次のユースケースでは、city が 'hangzhou' で age が 1 から 18 のデータを取得します。
SELECT name,id FROM myTable WHERE search_query = '+city:hangzhou +age:[1 TO 18]';CQL 構文の詳細については、「CREATE SEARCH INDEX」をご参照ください。
導入事例
注文シナリオ
物流、サードパーティ決済、モバイル旅行などのビジネスにとって、注文データの保存はコア要件です。注文データには、しばしば独自の特徴があります。
高い成長率:「独身の日」(Double 11) ショッピングフェスティバルやその他の大規模なセールプロモーション中など、データはいつでも爆発的に増加する可能性があります。
低コスト:注文データは一般的に直接的な経済的利益を生み出すものではなく、ビジネスの顧客にとっての付加価値です。したがって、低コストで保存する必要があります。
多次元クエリ:エンドユーザーは、さまざまな視点から注文を分類、タグ付け、表示、フィルターすることがよくあります。
以前は、これらの要件に対する一般的なソリューションは、MySQL と検索エンジンを組み合わせたものでした。ビジネスは両方のシステムに書き込むか、binlog を使用してリアルタイム同期を行いました。クエリは、異なるシステムから結果を取得しました。データ量が増えるにつれて、このアーキテクチャはホットデータ用に MySQL、コールドデータ用に Lindorm、そして検索エンジンという形に進化する可能性がありました。このマルチシステムアプローチはビジネス上の問題を解決できますが、複数のシステムを維持するための時間と労力のコストが伴います。
Lindorm は、これらの問題に対するワンストップソリューションを提供し、データフローを管理する必要性をなくし、アクセス用の統一された API を提供します。
コールド・ホットデータ分離、圧縮最適化などの方法により、ストレージコストを大幅に削減します。
水平スケーリングにより、大量のデータ書き込みに対応します。
SearchIndex CQL は、豊富なクエリ構文を提供します。
ユーザーペルソナ
ユーザーペルソナデータは、一般的に基本データと分析から派生したタグデータの2種類があります。このデータは、マーケティング、レコメンデーションなどのシナリオに適用でき、ビジネスの急速な収益成長を支援します。ペルソナデータの主な課題は次のとおりです。
大規模なデータ量:ペルソナデータはユーザーベースと強く相関しており、しばしば数千万から数億レコードに達します。データには非常に多くのディメンションもあります。一部の顧客シナリオでは、5,000 を超えるタグをサポートします。
高並行性:ペルソナデータはしばしば完全更新が必要であり、これは後続のレコメンデーションや広告配信などを効果的にサポートするために、ベースライン時間内に完了する必要があります。
動的カラム:データのディメンションは絶えず変化するため、システムは列の動的な追加と削除をサポートする必要があります。
多次元クエリ:ペルソナデータのクエリニーズは、ビジネス要件によって異なります。運用担当者は、しばしば任意のディメンションからのデータに対して統計を実行する必要があります。
プロファイルシナリオは、一般的に強力なトランザクションを必要としません。これらは、大規模なデータ量と高並行性の読み取り/書き込みが特徴であり、この組み合わせはリレーショナルデータベースには適していません。NoSQL データベースである Lindorm は、これらのシナリオに最適です。
複数のカラムファミリー、動的カラム、TTL などの機能は、テーブルスキーマが固定されておらず、頻繁に変更されるビジネスシナリオに適しています。
高性能スループット。
SearchIndex CQL は、任意のディメンションでのクエリと統計をサポートします。
ログ検索
ログは、システムログ、データベース監査ログ、行動ログなど、さまざまなソースから得られます。インターネット企業では、このデータはオープンソースの Elasticsearch (ES) に保存され、ELK スタックを使用してワンストップのロギングプラットフォームを構築することがよくあります。しかし、ES のストレージコストは非常に高く、ストレージとコンピュートはしばしば同じマシンに同居しています。大量のデータ量では、システムの運用保守は多くの課題に直面します。データ移行、ノードのスケーリングなどのタスクには手動介入が必要です。マルチモーダルデータベースである Lindorm の SearchIndex 機能は、ログ検索シナリオにとってより良い選択です。ワイドテーブルエンジンを使用して大量のデータを保存し、コストを削減し、検索エンジンを使用してインデックスを構築し、クエリを高速化します。統一された API は、ビジネス開発コストをさらに削減します。