類似画像検索問題
- 何百万もの画像がpHashされ、Elasticsearch に保存されています。
- フォーマットは "11001101...11" (長さ 64) ですが、変更できます (変更しないほうがよいでしょう)。
対象画像のハッシュ "100111..10" が与えられた場合、ハミング距離 8 以内で Elasticsearch インデックス内のすべての類似画像ハッシュを見つけたいと考えています。
もちろん、クエリは 8 より大きい距離の画像を返すことができ、Elasticsearch または外部のスクリプトは結果セットをフィルタリングできます。ただし、合計検索時間は 1 秒程度以内にする必要があります。
現在のマッピング
images
各ドキュメントには、画像ハッシュを含むネストされたフィールドがあります。
{
"images": {
"type": "nested",
"properties": {
"pHashFingerprint": {"index": "not_analysed", "type": "string"}
}
}
}
私たちの貧弱な解決策
事実: Elasticsearch ファジー クエリは、最大 2 のレーベンシュタイン距離のみをサポートします。
カスタム トークナイザーを使用して、64 ビット文字列を 16 ビットの 4 つのグループに分割し、4 つのファジー クエリで 4 つのグループ検索を実行しました。
アナライザ:
{
"analysis": {
"analyzer": {
"split4_fingerprint_analyzer": {
"type": "custom",
"tokenizer": "split4_fingerprint_tokenizer"
}
},
"tokenizer": {
"split4_fingerprint_tokenizer": {
"type": "pattern",
"group": 0,
"pattern": "([01]{16})"
}
}
}
}
次に、新しいフィールド マッピング:
"index_analyzer": "split4_fingerprint_analyzer",
次にクエリを実行します。
{
"query": {
"filtered": {
"query": {
"nested": {
"path": "images",
"query": {
"bool": {
"minimum_should_match": 2,
"should": [
{
"fuzzy": {
"phashFingerprint.split4": {
"value": "0010100100111001",
"fuzziness": 2
}
}
},
{
"fuzzy": {
"phashFingerprint.split4": {
"value": "1010100100111001",
"fuzziness": 2
}
}
},
{
"fuzzy": {
"phashFingerprint.split4": {
"value": "0110100100111001",
"fuzziness": 2
}
}
},
{
"fuzzy": {
"phashFingerprint.split4": {
"value": "1110100100111001",
"fuzziness": 2
}
}
}
]
}
}
}
},
"filter": {}
}
}
}
画像自体ではなく、一致する画像を持つドキュメントを返すことに注意してください。
問題は、他のドメイン固有のフィルターを追加して初期セットを減らした後でも、このクエリが何十万もの結果を返すことです。スクリプトは、ハミング距離を再計算する作業が多すぎるため、クエリに数分かかる場合があります。
予想どおり、3 と 4 に増やすminimum_should_match
と、検索する必要がある画像のサブセットのみが返されますが、結果のセットは小さくて高速です。== 3 では必要な画像の 95% 未満が返されますが、== 2minimum_should_match
の場合と同様に 100% (または 99.9%) が必要minimum_should_match
です。
n-gram で同様のアプローチを試みましたが、結果が多すぎるという同様の方法ではまだあまり成功していません。
他のデータ構造とクエリの解決策はありますか?
編集:
minimum_should_match
評価プロセスにバグがあり、 == 2 が 100% の結果を返すことに気付きました。ただし、その後の処理時間は平均5秒かかります。スクリプトを最適化する価値があるかどうかを確認します。