リレーショナルデータベースでのファジー検索

Webサイトやモバイルアプリケーションで必要な情報を検索するには、ユーザーがキーボードから自由に入力する単語やフレーズを検索することがよくあります(たとえば、リストから選択するのではなく)。 当然、ユーザーは間違いやタイプミスを犯す可能性があります。 この場合、ほとんどのデータベースに実装されているフルテキストインデックス、フルテキストインデックスでは、期待した結果が得られず、実用的ではありません。 そのような機能は、elasticsearchに基づいてますます実装されています。



elasticsearchを使用するソリューションには1つの大きな欠点があります-検索インデックスを保存するPostgreSQL、MySQL、mongodb、elasticsearchなどのメインデータベースで不一致の可能性が非常に高いです。



理想的なオプションは、メインデータベースの更新中に検索エンジンのデータベースが利用できなくなった場合に、データマッチング機能を引き継ぐ「ブリッジ」を持つことです。 しかし、そのようなブリッジの実装はまだ見つかっていません。 たとえば、mongodbとlucene バンドルプロジェクトの1つで 、この問題が言及されています。

LuMongoノードの通常のシャットダウンでは、すべてのセグメントがコミットされ、既存のノードに配布されます。 これにより、ノードをローリングシャットダウンして更新することができます。 予期しないシャットダウンでは、セグメントはコミットせずに既存のノードに失敗します。 これらのインデックスには、ロールバックまたは修復が必要になる場合があります。 現在、これは自動的に処理されませんが、今後のリリースではLuceneの組み込みのインデックス修復を使用して行われます。 ドキュメントはインデックスではなくMongoDBに保存されるため、別の解決策として、破損したセグメントのドキュメントを取得して、インデックスを再作成することができます。 MongoDBは、レプリケーションによるシームレスなフェイルオーバーも提供します。 MongoDBのレプリケーションは、データセンター全体でのデータセンター対応バックアップが可能です。
この問題は実際にはどのように解決されますか? まさか。 データがそれほど大きくない場合、データベースは単にタイマーによって再インデックス付けされます。 データベースが大きく、インデックスの再作成が不可能な場合は、すべてが一貫性のないままであるため、この不整合を明らかにすることは少し難しくなります。



elasticsearchまたはluceneで着実にインデックスを更新する安定した「ブリッジ」が遅かれ早かれ現れることを願っています。 現在、実用的なソリューションを見つける必要があります。



1つのオプションは、データの保存と検索に単一のデータベースを使用することです。 elasticsearchをこのような単一のデータベースとして使用することに関して、フォーラムでのほとんどすべての議論で、このようなソリューションは機能しないというコンセンサスがありました。 そこで、あいまい検索をサポートするフルテキストインデックスを作成できるデータベースを探し始めました。 このようなインデックスのメインエンジンであるluceneはJavaで開発されたため、このような機会を探したデータベースの輪は明確に概説されていました。



判明したように、luceneライブラリを使用し、poduction readyアプリケーションレベルにある少なくとも2つのソリューションがあります。これらはorientdbとh2です。



orientdbでは、ファジー全文検索の操作は非常に簡単です。



create class russian create property russian.message string create index russian.message on russian(message) fulltext engine lucene metadata { "analyzer": "org.apache.lucene.analysis.ru.RussianAnalyzer" } select * from russian where message lucene '~0.5' limit 2
      
      





h2では、もう少し複雑です。 インデックスは、メインテーブルを関連付ける必要がある別個のテーブルです。 しかし、もう少し複雑なことは難しくありません。



 CREATE ALIAS IF NOT EXISTS FTL_INIT FOR "org.h2.fulltext.FullTextLucene.init"; CALL FTL_INIT(); DROP TABLE IF EXISTS TEST; CREATE TABLE TEST(ID INT PRIMARY KEY, FIRST_NAME VARCHAR, LAST_NAME VARCHAR); CALL FTL_CREATE_INDEX('PUBLIC', 'TEST', NULL); INSERT INTO TEST VALUES(1, 'John', 'Wayne'); INSERT INTO TEST VALUES(2, 'Elton', 'John'); SELECT * FROM FTL_SEARCH_DATA('John', 0, 0); SELECT * FROM FTL_SEARCH_DATA('LAST_NAME:John', 0, 0);
      
      





apapacy@gmail.com

2018年4月22日



All Articles