Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Elasticsearch における類似度ベクトル検索のベストプラクティスを求めて/es-vector-search

Elasticsearch における類似度ベクトル検索のベストプラクティスを求めて/es-vector-search

Takahiko Ito

July 31, 2019
Tweet

More Decks by Takahiko Ito

Other Decks in Programming

Transcript

  1. Elasticsearch における類似度ベクトル検索の
    ベストプラクティスを求めて
    伊藤 敬彦

    View Slide

  2. 注意
    ● この発表の内容はたたき台的な位置づけです。
    ● もっと良い方法について知っている人があれば教えてください

    View Slide

  3. 自己紹介
    ● ソフトウェアエンジニア at クックパッド
    ● 博士(工学)
    ● 12年前に検索エンジンの会社(Fast Search & Transfer)に就職した後、検索エン
    ジンやデータマイニング界隈をフラフラしてます
    ● Twitter アカウント: takahi_i
    ● オープンソース:RedPen、Cookiecutter Docker Science

    View Slide

  4. ある日の会話
    ● 知人:「伊藤、お前検索やってたよな。類似画像検索、シュッと
    やりたいんだけど、どうしたらいいの?」
    ● 僕:「類似ベクトル検索かーーー。。。最近だと要望の多い使い
    方だし、Elasticsearchのデフォルト機能ですぐできるんちゃう
    ?」
    ● 僕:「うちのサービスで使うこともありそうなんで調べてみる
    かーーー。」

    View Slide

  5. 準備:関連検索
    ● テキスト文書の関連検索はメジャーな検索プラットフォーム(Solr、Elasticsearch)で
    サポートされている
    ● しかし、いろいろ調べたところ画像の類似度検索には決定打となるのが見つからな
    かった。。。。
    ● 既存のElasticsearch をベースにした画像の類似度検索
    ○ https://github.com/EdjoLabs/image-match
    ○ https://github.com/kzwang/elasticsearch-image
    ● 問題:ベクトルを古典的な手法(Hashing)で離散化する仕様
    ● 最新のEmbedding手法で生成したベクトルがそのまま使えない。。。

    View Slide

  6. 準備:Faiss
    ● Facebook によって開発された類似度検索用のパッケージ
    ● URL: https://github.com/facebookresearch/faiss
    ● 感想:よくできている。これで十分では?
    ○ メルカリさんも利用:
    https://speakerdeck.com/metalunk/merukariniokeru-ai-huo-yong-shi-li-pyc
    on-jp-2018?slide=21
    ● ただ、やはり検索プラットフォーム(ElasticsearchやSolr) で実現したい。。。

    View Slide

  7. Elasticsearchで実現したい理由
    ● Elasticsearchの運用しているチームは多い
    ○ 類似ベクトル検索単体で新しいパッケージを導入するのは敷居が高い
    ○ 普通のエンジニアリングチーム:検索エンジンの専任がいなかったり、いてもせ
    いぜい1人
    ○ Elasticsearchのプラグイン追加+インデクス追加ぐらいで実現したい
    ● 検索に関する補助機能を自作したくない(開発リソースがないチームが多い)
    :Sharding、Replication、Boosting、マルチテナント etc...

    View Slide

  8. まとめ:類似ベクトル検索パッケージに望むこと
    1. 速度
    ○ 高速に結果が帰ってほしい。検索にかかる時間がO(N)とか┐(´д`)┌
    2. 精度
    ○ 精度が悪いのはNG。できれば最近のEmbedded 手法使いたい
    3. 運用性
    ○ 空間木インデクスだけ与えられてるのはNG。。。。。
    ○ Elasticsaerch とか Solr がインデクスの Replication や Sharding とか提供して
    くれている時代に。。。
    ○ ほとんどの検索チームは専任一人がいいところ、シュッと構築できないと

    View Slide

  9. 調査 1
    ● 質門:Elasticsearchでベクトルの関連検索に利用できるパッケージがあるか?
    ● 回答:存在する
    ○ https://github.com/lior-k/fast-elasticsearch-vector-scoring
    ● 問題:検索に時間がかかる(O(N))
    ○ 一般的なWebサービスでは使えない

    View Slide

  10. 調査 2
    ● Elasticsaerch で高速に取ってくる手法はないか?
    ● 頑張って探したところ、ブログ記事を発見した
    ● URL:https://www.linkedin.com/pulse/searching-deep-learning-eike-dehling/
    ● 処理の流れ(二段階)
    ○ KD-木で粗く候補を取ってくるプラグイン
    ■ Lucene のKD 木インデクスを ESから利用できるようにした
    ■ NOTE: Lucene のKD木は8次元までしか対応していないので、絞り込み
    用に低次元ベクトルを別途用意する必要がある。。。
    ○ 候補とクエリに含まれるベクトルのコサイン類似度を計算してランキングし直す
    プラグイン(全ページで紹介したプラグインを利用する)

    View Slide

  11. 復習:空間木
    ● Wikipediaより: k次元のユークリッド空間にある点を分類する空間分割データ構造
    である。kd木は、多次元探索鍵を使った探索(例えば、範囲探索や最近傍探索)な
    どの用途に使われるデータ構造である
    ● 平たく言うと:入力ベクトルに類似するベクトル郡を高速(O(Log(N)))に取得できる
    ● 実はLuceneでサポートされている
    ○ See
    https://mocobeta-backup.tumblr.com/post/142559495812/hello-lucene-
    600
    ○ 先のプラグインはLuceneが提供するKD木を使用して絞り込み検索をする

    View Slide

  12. 実験
    ● word2vec で単語のベクトル(8次元、200次元)を作成してESへの入力
    とする(画像とは。。。。)
    ○ 10万単語
    ○ 画像データで実験する時間が取れず。。。

    View Slide

  13. ES のマッピング(スキーマ)
    ポイント:二種類のベクトルを保持するフィー
    ルド作る
    - 低次元ベクトル(8次元)
    - 高次元ベクトル(200次元)
    {
    "mappings": {
    "doc": {
    "properties": {
    "name" : {"type": "text"},
    "reduced_vector": {
    "type": "vector",
    "dimensions": 8
    },
    "full_vector": {
    "type": "binary",
    "doc_values": true
    }
    }
    }
    }
    }

    View Slide

  14. インデクス
    ● Python 用ESクライアントでword2vecから算出されたベクトル(8次元、200次元)
    をESインスタンスにインデクスする。
    es.index("full_vectors", "doc",
    { "name": vocab,
    "reduced_vector": ",".join([str(x) for x in vector8]),
    "full_vector": base64.b64encode(np.array(vector200).
    astype(np.dtype('>f8'))).decode("utf-8"),
    })

    View Slide

  15. 検索クエリ
    {
    "query": {
    "function_score": {
    "query": {
    "range": {
    "reduced_vector": {
    "from": from_vector,
    "to": to_vector
    }
    }
    },
    "functions": [
    {
    "script_score": {
    "script": {
    "source": "staysense",
    "lang" : "fast_cosine",
    "params": {
    "field": "full_vector",
    "cosine": True,
    "vector" : target_full_vector
    }
    }
    }
    }
    ],
    "boost_mode": "replace"
    }
    }}
    第一段階の処理:rangeクエリ
    でターゲットベクトルを含むベク
    トル部分空間を指定(次ページ
    で解説)
    第二段階の処理:第一段階
    の処理で粗く取得された候補
    を cosine でリランキング

    View Slide

  16. 絞り込み検索用ベクトルの作成
    ● KD木で抽出する部分空間(入力ベクトルが内部に存在する部分空間)作
    る必要がある。
    ● 上限ベクトル、下限ベクトルを指定する
    def generate_ranges(vector):
    from_vector = [element -2.5 for element in vector]
    to_vector = [element + 2.5 for element in vector]
    return ",".join([str(x) for x in from_vector]), ",".join([str(x) for x in to_vector])
    下限ベクトル(入
    力ベクトルの要
    素から定数を引
    いたもの)
    上限ベクトル(入
    力ベクトルの要
    素に定数を足し
    たもの)

    View Slide

  17. 結果:グラタン
    ランキング 単語
    1 グラタン
    2 ベシャメルソース
    3 ソテー
    4 クロワッサン
    5 フィリング

    View Slide

  18. 結果:落胆
    ランキング 単語
    1 落胆
    2 驚愕
    3 決心
    4 あきらめ
    5 裏切ら

    View Slide

  19. デモ
    ● 脱脂粉乳
    ● 麻耶
    ● グラタン

    View Slide

  20. 結果
    ● 速度はまあまあ
    ○ 近傍の距離に依存する
    ● 精度もとりあえず、似たのは取れている

    View Slide

  21. 課題
    ● 絞り込みベクトルの大きさが8次元で固定
    ○ Lucenceを再ビルドすると大きさを変更できるらしい(要検証)
    ○ https://github.com/textkernel/vector-search-plugin#intended-use-case に
    よると ‘by default 8, you can re-compile lucene with higher values..’ とは書
    いてある。。。
    ● ベクトルと、超低次元ベクトルの2つを作るのが面倒
    ○ REST API にベクトル入れるとよしなに低次元ベクトルを作ってくれるとより便
    利そう
    ○ 入力の高次元ベクトルに対して、低次元ベクトル数でmodを取得し足し合わせ
    るとか

    View Slide

  22. 今回の実験
    ● 実験で使ったレポジトリ
    ○ 関連するプラグインを同梱したもの(KD木による絞り込み、コサイン類似度、イ
    ンデクス、検索 REST API 経由での文書追加)
    ○ URL: https://github.com/takahi-i/es_embedded_vector_search
    ● 自分では検証、改善する時間が取れないので、そのうち消します

    View Slide

  23. お願い
    ● このやり方、Elasticsearchを利用してできるんで、よさそうではある
    ● 使えるようであれば、だれか洗練されたESプラグインを作ってくれると嬉しい(質門
    をくれた知人にはそれを推薦したい)

    View Slide

  24. まとめ
    ● Elasticsearch で(ある程度)高速に類似画像検索をする方法についていて調査、
    検証しました
    ● (ある程度)簡単にElasticsearch上でKD木を併用した方法ができる
    ○ 2つベクトルフィールドを保持しないといけないけど。。。。
    ○ とはいえ、Elasticsearchの提供する機能を利用できるのは良さそう

    View Slide

  25. ご清聴ありがとうございました

    View Slide