画像の知覚的ハッシュを含む大規模なデータベース(1600万行)があります。
妥当な時間枠内で ハミング距離 で行を検索できるようにしたいと思います。
現在、私が問題を適切に理解している限り、ここでの最良のオプションは BK-Tree を実装するカスタムSP-Gist実装であると思いますが、それは多くの作業のように思えます。カスタムインデックスを適切に実装する実際の詳細については、まだあいまいです。しかし、ハミング距離の計算は十分扱いやすく、IdoはCを知っています。
基本的に、ここで適切なアプローチとは何ですか?ハッシュの特定の編集距離内で一致を照会できるようにする必要があります。私が理解しているように、等しい長さの文字列とのレーベンシュタイン距離は機能的にハミング距離であるため、少なくともsome必要なものがサポートされていますが、それからインデックスを作成する明確な方法(変更を照会している値を思い出してください。固定値からの距離を事前に計算することはできません。これは、その1つの値に対してのみ役立つためです)。
ハッシュは現在、ハッシュのバイナリASCIIエンコーディング)を含む64文字の文字列として格納されていますが(たとえば、 "10010101 ...")、それらをint64に簡単に変換できます。問題は、比較的高速にクエリを実行できる必要があることです。
pg_trgm
を使用して、私が望むものに沿って何かを達成することは可能であるように思われるかもしれませんが、トライグラムマッチングのメカニズムがどのように機能するか(特に、それが返す類似性メトリックは実際には何を表していますか?これは、編集距離のようなものです)。
挿入のパフォーマンスは重要ではありません(各行のハッシュを計算するのは非常に計算コストがかかります)ので、主に検索に注意します。
モア回答!
さて、ようやく時間をかけてカスタムPostgreSQLインデックス拡張を作成しました。 SP-Gistインターフェース を使用しました。
これは、Posgresがbigであるため、かなり困難でした。
とにかく、いつものように、それはgithub here にあります。
パフォーマンスに関しては、この質問に対する他の回答では、純粋にメモリ内の実装よりも現在2〜3倍遅くなっていますが、使用する方がはるかに便利です。 ms/query-150 ms/query(これはまだかなり小さい)。
まあ、私はカスタムpostgres C拡張の作成にしばらく時間を費やし、BKツリー構造をメモリに維持するCythonデータベースラッパーを作成するだけで終わりました。
基本的に、データベースからのphash値のメモリ内コピーを保持し、データベースへのすべての更新がBKツリーに再生されます。
すべてはgithub here にあります。また、たくさんの単体テストがあります。
距離が4のアイテムの1000万ハッシュ値のデータセット全体に対してクエリを実行すると、ツリー内の値の約0.25%〜0.5%が影響を受け、約100ミリ秒かかります。