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

Elasticsearchを用いたPOI検索入門

Tomoki Saito
November 17, 2022

 Elasticsearchを用いたPOI検索入門

タクシー乗務員の営業業務利用を背景としたPOI検索について、Elasticsearchを用いた実現方法や良くある問題に対する改善アプローチについて紹介する。

Tomoki Saito

November 17, 2022
Tweet

Other Decks in Technology

Transcript

  1. 2 自己紹介 ▪ 齋藤 智輝 (@tstomoki ) ▪ 職歴 ▪

    ヤフー株式会社 ▪ エンティティパネルの開発 ▪ ユーザ位置情報を用いた研究開発 ▪ 画像系ベンチャー企業 ▪ 機械学習モデルの開発・導入 ▪ 株式会社Mobility Technologies (2019/10 ~) AI技術開発部 アルゴリズムグループ ▪ ETA (迎車時間予測エンジンの開発) ▪ AI予約 ・優先パス, etc. 趣味 ▪ サバゲー(最近) ▪ サウナ ▪ サイクリング (ロードバイク)
  2. 5 POIとは Point of Interest の略 一般的に POI というと「目標物」を指すことが多く、地図データベースや カーナビゲーションシステムにおいては、店舗や施設を意味し、この数が

    多いほど情報が豊富であるということになります。 背景: POIとは cf. esriジャパン,「POI」https://www.esrij.com/gis-guide/gis-other/point-of-interest/
  3. 7 1. 表記ゆれ 例. ナイキストア, nikeストア, 一丁目, 1丁目, etc. 2.

    距離制限 例. 大阪周辺で、「空港」と検索 => 「成田空港」 東京駅周辺で、「スシロー」と検索 => 「スシロー帯広店」 3. 別称・通称 例.「成田国際空港」: 「成田空港, 新東京国際空港, NRT, ...」 「ビッグサイト」: 「東京国際展示場, 東京ビッグサイト, ...」 4. 打ち間違い 例. 「木更津」=> 「きさらず」?「きさらづ」? 背景: 問題の難しさ
  4. 9 「ウェブ検索クエリに対する教師なしエンティティリンキング」(ヤフー) 知識ベース (Knowledge Base, KB) を用いて実現 曖昧性をウェブクリックログから構築した確率モデルで回避 論文紹介 クエリ「増上寺」に対する

    エンティティパネル 論文リンク Entity 増上寺 三縁山広度 院増上寺 東京都港区芝公園4丁目7番35号 https://www .zojoji.or.jp/ 35.39267, 139.44538 名称 別称 所在地 公式サイト 座標 エンティティの構造化された情報
  5. 15 ▪ “name” fieldへの完全一致(1語のみ) ▪ “name” fieldへの完全一致(複数語) ▪ “name” fieldへのAND検索

    ▪ “name” fieldへの部分一致(ワイルドカード指定) 基本的なクエリ: 単一field {"query": {"term": {"name": "成田空港"}}} {"query": {"terms": {"name": ["成田空港", "成田国際空港"]}}} {"query": {"match": {"name": {"query": "成田 国際 空港"}}}} {"query": {"wildcard": {"name": "*成田空港*"}}
  6. 16 ▪ カテゴリ指定をした“name”への完全一致 基本的なクエリ: 複数条件 { "query": { "bool": {

    "should": [ { "match": { “name”: "東京ドーム" } }, { "terms": { "categories": [ "poi0" ] } } ] } } } これだと以下のいずれかを満たす • name が “東京ドーム” に完全一致 • カテゴリが poi0 must : 必ず含まれる条件 must_not : 条件を満たすものを除外 should : いずれかの条件を満たす filter : 条件を満たすものに絞る
  7. 17 ▪ カテゴリ指定をした“name”への完全一致 基本的なクエリ: 複数条件 { "query": { "bool": {

    "must": [ { "match": { "name" : "東京ドーム" } } ], "filter": [ { "terms": { "categories": [ "poi0" ] } } ] } } } • name が “東京ドーム” に完全一致 • カテゴリ poi0 に絞る must : 必ず含まれる条件 must_not : 条件を満たすものを除外 should : いずれかの条件を満たす filter : 条件を満たすものに絞る
  8. 18 ▪ 距離制限にも対応 ▪ 指定方法 ▪ 起点となる座標 ▪ 検索対象とする範囲 ▪

    半径 ▪ Range ▪ Bounding box ▪ polygon 基本的なクエリ: 距離制限 検索地点 半径 検索対象のPOI 検索対象外のPOI
  9. 19 ▪ 5km以内の“name”への完全一致 基本的なクエリ: 距離制限 { "query": { "bool": {

    "must": [ { "wildcard": { "name": { "value": "*セブンイレブン*" } } } ], "filter": { "geo_distance": { "distance": "5km", "location": { "lat": 35.681427924515276, "lon": 139.7670926134856 } } } } } } 検索位置から5km以内のセブンイレブンを検索できる!
  10. 20 ▪ 類似スコアの計算 (公式ドキュメント) ▪ BM25 (okapi BM25, default) ▪

    TF/IDFベースの類似度 ▪ 文書に含まれる単語数が多いとペナルティ ▪ DFR: Divergence From Randomness framework ▪ DFI: Divergence From Independence ▪ 頻出単語に重み付けした確率モデル ▪ IB: Information Based model ▪ トピックモデルベースの文書モデル 基本的なクエリ: スコア計算
  11. 21 ▪ tf-idfの拡張 okapi BM25 𝑠𝑐𝑜𝑟𝑒 𝑑, 𝑄 = *

    !"# $ 𝐼𝐷𝐹 𝑞! , 𝑑 ⋅ 𝑓 𝑞! , 𝑑 ⋅ (𝑘# + 1) 𝑓 𝑞! , 𝑑 + 𝑘# ⋅ 1 − 𝑏 + 𝑏 ⋅ 𝑑 𝑎𝑣𝑔𝑑𝑙 𝐼𝐷𝐹 𝑞, 𝑑 = log 文書の総数 𝑞が含まれる文書数 𝑠𝑐𝑜𝑟𝑒 𝑑, 𝑄 = * !"# $ 𝐼𝐷𝐹 𝑞! , 𝑑 ⋅ 𝑇𝐹(𝑞! , 𝑑) 𝑇𝐹 𝑞, 𝑑 = 𝑓(𝑞, 𝑑) 𝑑に含まれる単語数 = 𝑑における𝑞の出現頻度 𝑑に含まれる単語数 tf-idf: BM25: ここが異なる 𝑑: 文書(𝑃𝑂𝐼の名称)
  12. okapi BM25 の解釈 𝑓 𝑞! , 𝑑 ⋅ (𝑘" +

    1) 𝑓 𝑞! , 𝑑 + 𝑘" ⋅ 1 − 𝑏 + 𝑏 ⋅ 𝑑 𝑎𝑣𝑔(𝑑𝑙) 文書𝑑における𝑞の出現頻度 文書𝑑の単語数 定数 文書全体の平均単語数 文書𝑑の相対的な長さ
  13. 23 ▪ ある文書dが平均的な長さだと仮定して検証 okapi BM25 の解釈 𝑓 𝑞! , 𝑑

    ⋅ (𝑘# + 1) 𝑓 𝑞! , 𝑑 + 𝑘# ⋅ 1 − 𝑏 + 𝑏 ⋅ 𝑑 𝑎𝑣𝑔(𝑑𝑙) = 𝑓 𝑞! , 𝑑 ⋅ (𝑘# + 1) 𝑓 𝑞! , 𝑑 + 𝑘# ⋅ 1 − 𝑏 + 𝑏 ⋅ 𝑎𝑣𝑔(𝑑𝑙) 𝑎𝑣𝑔(𝑑𝑙) ∵ 𝑑 = 𝑎𝑣𝑔(𝑑𝑙) = 𝑓 𝑞! , 𝑑 ⋅ (𝑘# + 1) 𝑓 𝑞! , 𝑑 + 𝑘# ⋅ 1 − 𝑏 + 𝑏 = 𝑓 𝑞! , 𝑑 ⋅ (𝑘# + 1) 𝑓 𝑞! , 𝑑 + 𝑘# 出現頻度が高すぎるスコアを抑制する効果がある
  14. 24 ▪ ある文書dの長さによってどう変化するか okapi BM25 の解釈 𝑓 𝑞! , 𝑑

    ⋅ (𝑘# + 1) 𝑓 𝑞! , 𝑑 + 𝑘# ⋅ 1 − 𝑏 + 𝑏 ⋅ 𝑑 𝑎𝑣𝑔(𝑑𝑙) = 𝑓 𝑞! , 𝑑 ⋅ (𝑘# + 1) 𝑓 𝑞! , 𝑑 + 𝑘# ⋅ 1 − 𝑏 + 𝑏𝑥 相対的に短い文書(name)を重視することができる こちらが重視される “東京駅” “セブンイレブン東京駅前店”
  15. 26 ▪ RESTfulな手法 ▪ POI情報を1件登録 ▪ 複数のPOI情報を一括登録 インデックス POI インデックス

    { "name": "六本木グランドタワー" "category": "POI1" } POST /<index名>/_doc POST _bulk { "index" : { "_index" : " <index名> ", "_id" : "1" } } { ”name" : "六本木グランドタワー", "category": "POI1"} { "index" : { "_index" : " <index名> ", "_id" : "2" } } { ”name“ : ”六本木一丁目駅", "category": "POI2"} POST /<index名>/_bulk
  16. 29 ▪ データのインデックス作成時や検索時に形態素解析を用い ることができる ▪ POI情報登録時 ▪ POI検索時 形態素解析器の利用 入力クエリ:

    「東京駅ファミリーマート」 検索クエリ: • 「東京駅ファミリーマート」 • 「東京駅 ファミリーマート」 • 「東京 駅 ファミリーマート」 わかちがき: 「ファミリーマート 東京駅 前 店 」 元名称: 「ファミリーマート東京駅前店」 登録名称: • 「ファミリーマート 東京駅前店」
  17. 30 ▪ Analyzerとして文字列正規化フローを定義できる ▪ “kana_analyzer” ▪ 記号の削除 ▪ 小文字に変換 ▪

    Unicode正規化, etc. 文字列正規化 “神谷バー★Tokyo Base★店” “神谷バー tokyo base店”
  18. 31 ▪ 導入済みanalyzerの結果を確認できる ▪ “東京駅” を分かち書き(tokenize) ▪ “東京駅” をかな変換 &

    分かち書き(tokenize) Analyzerの動作確認 { ”analyzer“: <analyzer名>, ”text“: ”東京駅" } POST /<index名>/_analyze 東京 駅 { ”analyzer“: <analyzer名>, ”text“: ”東京駅" } POST /<index名>/_analyze とうきょう えき
  19. 33 1. 表記ゆれ 例. ナイキストア, nikeストア, 一丁目, 1丁目, etc. 2.

    距離制限 例. 大阪周辺で、「空港」と検索 => 「成田空港」 東京駅周辺で、「スシロー」と検索 => 「スシロー帯広店」 3. 別称・通称 例.「成田国際空港」: 「成田空港, 新東京国際空港, NRT, ...」 「ビッグサイト」: 「東京国際展示場, 東京ビッグサイト, ...」 4. 打ち間違い 例. 「木更津」=> 「きさらず」?「きさらづ」? 背景: 問題の難しさ (再掲)
  20. 34 1. 表記ゆれ 例. ナイキストア, nikeストア, 一丁目, 1丁目, etc. 2.

    距離制限 例. 大阪周辺で、「空港」と検索 => 「成田空港」 東京駅周辺で、「スシロー」と検索 => 「スシロー帯広店」 3. 別称・通称 例.「成田国際空港」: 「成田空港, 新東京国際空港, NRT, ...」 「ビッグサイト」: 「東京国際展示場, 東京ビッグサイト, ...」 4. 打ち間違い 例. 「木更津」=> 「きさらず」?「きさらづ」? 背景: 問題の難しさ への対応 正規化 + 別称追加 距離制限 / 減衰スコア 別称追加 クエリ拡張
  21. 35 ▪ それぞれの名称に対する別称・通称を集めたい ▪ Wikidataが使えそう ▪ Pros ▪ 商用利用可能 ▪

    ダンプデータも提供 ▪ SPARQLでデータ取得も可能 ▪ 誰でも編集可能 ▪ Cons ▪ 誰でも編集可能 ▪ ノイズが多い 別称追加 Wikidataでの「成田国際空港」の名称・別称
  22. 38 ▪ 減衰(Decay)関数を定義する ▪ 検索対象は絞らず検索スコアに反映 ▪ クエリ例 ▪ 東京駅とloc間の距離を対象 ▪

    2km以内であれば減衰なし ▪ Scale, decayで減衰率を調整 距離減衰スコアの導入 "DECAY_FUNCTION": { "location": { "origin": "35.68191, 139.76693", "scale": "10km", "offset": "2km", "decay": 0.7 } }
  23. 39 ▪ 減衰(Decay)関数を定義する ▪ DECAY_FUNCTIONはgauss, exp, linearの3つから指定できる 距離減衰スコアの導入 𝜎! =

    − 𝑠𝑐𝑎𝑙𝑒! 2 ⋅ ln(𝑑𝑒𝑐𝑎𝑦) 𝑆 𝑑𝑜𝑐 = 𝑒𝑥𝑝 − max 0, 𝑙𝑜𝑐"#$ − 𝑜𝑟𝑖𝑔𝑖𝑛 − 𝑜𝑓𝑓𝑠𝑒𝑡 ! 2𝜎! gauss 𝑆 𝑑𝑜𝑐 = 𝑒𝑥𝑝 𝜆 ⋅ max(0, 𝑙𝑜𝑐"#$ − 𝑜𝑟𝑖𝑔𝑖𝑛 − 𝑜𝑓𝑓𝑠𝑒𝑡) exp 𝜆 = ln(𝑑𝑒𝑐𝑎𝑦) 𝑠𝑐𝑎𝑙𝑒 linear 𝑠 = 𝑠𝑐𝑎𝑙𝑒 (1.0 − 𝑑𝑒𝑐𝑎𝑦) 𝑆 𝑑𝑜𝑐 = 𝑚𝑎𝑥 𝑠 − max(0, 𝑙𝑜𝑐"#$ − 𝑜𝑟𝑖𝑔𝑖𝑛 − 𝑜𝑓𝑓𝑠𝑒𝑡) 𝑠 , 0 cf. elastic, “Supported decay functions”
  24. 42 ▪ 管理方法は以下の2つ ▪ ファイルベース ▪ configディレクトリにファイルを設置 ▪ インデックスベース ▪

    “synonyms” fieldにそのまま記載 ▪ 書き方 類義語登録の利用方法 { "settings": { "index": { "analysis": { "analyzer": { "synonym_analyzer": { "tokenizer": "whitespace", "filter": [ "my_synonyms" ] } }, "filter": { "my_synonyms": { "type": "synonym", "synonyms_path": "my_synonyms.txt", "updateable": true } } } } } } cf. elastic, “違い”を生む“同じ”:Elasticsearchのパワーを増大させる“同義語” きさらず,きさらづ 入力: 「きさらず」検索: 「きさらず」「きさらづ」 きさらず => きさらづ 入力: 「きさらず」検索: 「きさらづ」
  25. 43 ▪ elasticsearchについて基本的な利用方法について紹介 ▪ クエリ構築方法 ▪ インデックス方法 ▪ 形態素解析(Analyzer)の利用方法 ▪

    POI検索の文脈で発生しがちな問題について の対応例を紹介 ▪ 別称追加 ▪ 減衰関数 ▪ 類義語辞書の利用 まとめ