2

ユーザーからの自由形式のクエリが与えられた場合、場所のフレーズが含まれているかどうかを判断しようとしています。

例: フリーフォーム クエリ「カリフォルニア州サンフランシスコのニューヨーク スタイル ピザ」と、「デンバー コ」、「マイアミ フロリダ」、「ニューヨーク シティ ニューヨーク」、「サンフランシスコ カリフォルニア」などの場所のフレーズを含むドキュメントのインデックスが与えられた場合、「paris france」などの場合、一致はロケーション フレーズ「san francisco ca」を含むドキュメントになります。

ロケーション フレーズを含むインデックスには、別のドキュメントに許容される順列も含まれます。上記の例では、"san francisco ca"、"san francisco california"、および場合によっては "sf ca"、"bay area ca" など、すべてインデックス内の個別のドキュメントとして含めることができます。大文字と小文字の区別と句読点は前もって破棄されるため、「カリフォルニア州サンフランシスコのニューヨーク スタイルのピザ」というクエリは「カリフォルニア州サンフランシスコのニューヨーク スタイルのピザ」になります。

また、「都市」と「州」と「国」をさまざまなフィールドに含めるなど、特定のタイプのクエリでこれを機能させるために場所にインデックスを付けるためのより良い方法または必要な方法がある場合は、私が行うことができますそれもまた、私は提案を非常に受け入れています。

私がこれまでに試したこと:

  1. プレーンな古い一致クエリ。最適に動作するように見えますが、順序付けは無視されます...「san francisco ca」は一致しますが、「ca francisco san」は一致しないはずです。位置も無視します。
  2. フレーズ一致。入力クエリに余分な用語 (「ニューヨーク スタイルのピザ」) が含まれているため、一致するものが得られないため、まったく機能しません。
  3. マルチフィールドマッチ、cross_fields オプション。一致クエリと同じ問題。順序と位置を無視します。これは、"city" と "state" などが異なるフィールドであるインデックスのバージョンで試みられました。
  4. 浸透。まったく仕事に就けませんでした。呼び出し GET .../_percolate は、インデックス内のすべてのドキュメントを取得します。また、.percolator タイプのビルドは非常に遅く、バルク API を使用してインスタンスをクラッシュさせました (JVM メモリ 99%)。私のデータベースには約 100 万の場所があり、約 120K の場所で一貫してクラッシュする percolator には多すぎると思います。私が読んだことから、これはパーコレーターの適切な使用例ではないと思いますが、よくわかりません。

私が試していないこととその理由:

  1. 帯状疱疹。特定の場所に含まれる用語の数は可変であり (つまり、「ダラス テキサス」、「サンフランシスコ カリフォルニア」、「ニューヨーク市、ニューヨーク」など)、帯状疱疹は特定の数の用語で機能するようです。
  2. クエリ文字列。ユーザーがフレーズを二重引用符で囲む必要はありません。また、クエリ言語 (OR、AND など) も必要ありません。また、位置を無視します。

私はこの問題を解決するのに 3 ~ 4 日を費やしました。サンプルのクエリ/インデックス/マッピングは素晴らしいですが、使用する必要があるクエリの種類 (およびインデックス作成とマッピング) を教えてくれるだけでも非常に役立つので、少なくとも「適切なツリーを作成する」ことができます!

他のツールがオープンソースであり、自由に利用でき、適切にサポートされ、使用されている限り、ES と組み合わせて他のツールを使用することにオープンです。位置データベースには最大 100 万件のレコードが含まれています。

おまけ: ロケーション フレーズがある場合は、クエリの最後にあると想定しています。それを感知するか、それに応じて結果を後押しする何らかの方法は素晴らしいでしょう. これを絶対的な要件にしたくないことに注意してください。ユーザーが「ニューヨーク スタイルのピザを提供しているサンフランシスコ カリフォルニア州のピザ店が欲しい」というクエリを送信した場合、前述のインデックスが指定された唯一の有効なロケーション フレーズは「サンフランシスコ カリフォルニア州」であり、一致するはずです。

ボーナス 2X: 各場所の人口情報があります。人口が多い場合に結果をわずかにブーストする方法も素晴らしいでしょう (field_value_factor 関数と ln1p 修飾子を使用して function_score を試してみましたが、うまく機能しているように見えますが、パーコレーターを使用した場合にどのように機能するかはわかりません)。

BONUS 3X!: 「san francsco」などのわずかなタイプミスに対応できるとよいでしょう。

ElasticSearch 1.3.2 を使用しています。

ありがとうございました!!

編集:明確にするために、ここでうまく説明されているように、インデックス付きのフレーズがクエリよりも短い場合、フレーズ検索を探していますが、残念ながら完全には解決されていません:

Solr: インデックス付きフレーズがクエリより短い場合のフレーズ検索

4

1 に答える 1

0

ここにいくつかの提案があります。疑問がある場合でも、あなたの要件が正しいことを理解しています。

基本的な考え方は、ドキュメントに実際に保存するものよりも大きなものに一致させたいため、インデックス (場所) に入れるものを操作することです。また、これが 1 つの (正しい) 回答が得られるか、まったく回答が得られないという白黒の状況になるとは思わないことを強調したいと思います。試合には常に「スコア」があります。

もう 1 つのポイントは、場所を操作する方法を知っておく必要があることです。これにより、ユーザーが使用すると予測されるクエリが与えられたときに、それらの操作がほとんどの場合 (すべての場合ではありません) に役立ちます。より良い言い方をすれば、インデックス付けされた場所とそれらに対して実行した操作の組み合わせにより、ほとんどのクエリに一致する可能性が高くなります。

ここにいくつかの具体的なアイデアがあります:

  1. 帯状疱疹を使用してください。これが、順序付けられた用語の概念を持つ唯一のオプションだと思います。あなたは自由形式のクエリがあると言いました。これは、クエリにそのクエリだけを入れ、用語に分割せず、ストップワードを削除したり、そのようなことをしたくないことを意味します。これは、順序を与えることができるspan_nearを使用できないことを意味します。

    帯状疱疹を使用すると、ユーザーが「ca francisco san」と入力する状況も解消されます。

  2. 最初の場所操作のアイデア: 完全な場所名も保存します (上記の帯状疱疹以外)。これにより、ロケーション ドキュメントと実際に完全に一致するクエリのスコアが少し高くなります。そして、あなたの例から、場所の複数の組み合わせがあることがわかったので、「場所」インデックスの「品質」が良好な一致結果をもたらす可能性が高くなります。

  "settings": {
    "analysis": {
      "filter": {
        "my_shingle_filter": {
          "type": "shingle",
          "min_shingle_size": 2,
          "max_shingle_size": 2,
          "output_unigrams": true // this is true for situations where you have "paris france" in locations but user searches for "paris"
        }
      },
      "analyzer": {
        "my_shingle_analyzer": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": [
            "lowercase",
            "my_shingle_filter"
          ]
        }
      }
    }
  },
  "mappings": {
    "locations": {
      "properties": {
        "name": {
          "type": "string",
          "analyzer": "my_shingle_analyzer",
          "fields": {
            "full": {
              "type": "string",
              "analyzer": "keyword"
            }
   }}}}}
  1. マッピング変換を使用して、場所のインデックスの品質を向上させます。name.fullつまり、上記の操作 -クエリされた用語に関連する予測に基づいて(上記と同様に) インデックスにフィールドを追加します。

    最初の例は、「カリフォルニア州サンフランシスコのニューヨーク スタイルのピザ」というクエリ サンプルの 1 つから派生したものです。inインデックス内の場所ごとに、プレフィックスを持つ必要がある別のフィールドを追加します:in san franciscoなどin new york

"transform": [
        {
        "script": "full_plus_in = 'in ' + ctx._source['name']; ctx._source['name.full_plus_in'] = full_plus_in",
        "lang": "groovy"
        }
...

2 番目の例はplaces、マッピングの新しいフィールドに接尾辞を追加することです。ここで、「新しいスタイルのピザを提供するサンフランシスコの場所」などのクエリが予測で頻繁に使用されると仮定すると、次のようになります。

{"script": "full_plus_places = ctx._source['name'] + ' places'; ctx._source['name.full_plus_places'] = full_plus_places",
        "lang": "groovy"}

ここにすべてをまとめると、予備的なマッピングになります。

{
  "settings": {
    "analysis": {
      "filter": {
        "my_shingle_filter": {
          "type": "shingle",
          "min_shingle_size": 2,
          "max_shingle_size": 2,
          "output_unigrams": true
        }
      },
      "analyzer": {
        "my_shingle_analyzer": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": [
            "lowercase",
            "my_shingle_filter"
          ]
        }
      }
    }
  },
  "mappings": {
    "locations": {
      "transform": [
        {
        "script": "full_plus_in = 'in ' + ctx._source['name']; ctx._source['name.full_plus_in'] = full_plus_in",
        "lang": "groovy"
        },
        {"script": "full_plus_places = ctx._source['name'] + ' places'; ctx._source['name.full_plus_places'] = full_plus_places",
        "lang": "groovy"}
        ],
      "properties": {
        "name": {
          "type": "string",
          "analyzer": "my_shingle_analyzer",
          "fields": {
            "full": {
              "type": "string",
              "analyzer": "keyword"
            },
            "full_plus_in": {
              "type": "string",
              "analyzer": "keyword"
            },
            "full_plus_places": {
              "type": "string",
              "analyzer": "keyword"
            }
          }
        }
      }
    }
  }
}

テストデータ:

{"index":{}}
{"name":"denver co"}
{"index":{}}
{"name":"miami fl"}
{"index":{}}
{"name":"new york city ny"}
{"index":{}}
{"name":"san francisco ca"}
{"index":{}}
{"name":"paris france"}
{"index":{}}
{"name":"bay area ca"}
{"index":{}}
{"name":"dallas texas"}
{"index":{}}
{"name":"san francisco california"}
{"index":{}}
{"name":"new york city new york"}

サンプルクエリ:

{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "name": "i want san francisco ca places having new york style pizza"
          }
        }
      ],
      "should": [
        {"match": {
          "name.full": "i want san francisco ca places having new york style pizza"
        }},
        {"match": {
          "name.full_plus_in": "i want san francisco ca places having new york style pizza"
        }},
        {"match": {
          "name.full_plus_places": "i san francisco ca places having new york style pizza"
        }}
      ]
    }
  }
}

そして、最初に一致した場所が最適である必要があります (取得したスコアを考慮して)。

于 2014-11-07T10:03:38.270 に答える