如何匹配多个单词作为标记前缀

use*_*421 4 elasticsearch

我想接受像“jan do”这样的查询,并让它匹配像“jane doe”、“don janek”这样的值——当然还有:“jan do”、“do jan”。

所以目前我能想到的规则是:

  1. 基于非字母数字值(例如空格、符号、标点符号)标记查询
  2. 每个查询标记充当数据存储中匹配标记的前缀
  3. 令牌出现的顺序无关紧要。更喜欢“jan do”而不是“do jan”会很好

到目前为止,我有这个映射

PUT /test
{
  "settings": {
    "analysis": {
      "analyzer": {
        "my_keyword": {
          "type": "custom",
          "tokenizer": "keyword",
          "filter": [
            "asciifolding",
            "lowercase"
          ]
        }
      }
    }
  },
  "mappings": {
    "question": {
      "properties": {
        "title": {
          "type": "string"
        },
        "answer": {
          "type": "object",
          "properties": {
            "text": {
              "type": "string",
              "analyzer": "my_keyword",
              "fields": {
                "stemmed": {
                  "type": "string",
                  "analyzer": "standard"
                }
              }
            }
          }
        }
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

我一直在搜索词组:

POST /test/_search
{
  "query": {
    "dis_max": {
      "tie_breaker": 0.7,
      "boost": 1.2,
      "queries": [
        {
          "match": {
            "answer.text": {
              "query": "jan do",
              "type": "phrase_prefix"
            }
          }
        },
        {
          "match": {
            "answer.text.stemmed": {
              "query": "jan do",
              "operator": "and"
            }
          }
        }
      ]
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

当事情真正开始该短语时,这可以正常工作,但现在我想标记查询并将每个标记视为前缀。

有没有办法做到这一点(可能在查询时)?

我的另一个选择是构建一个这样的查询:

POST test/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "prefix": {
            "answer.text.stemmed": "jan"
          }
        },
        {
          "prefix": {
            "answer.text.stemmed": "do"
          }
        }
      ]
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

这似乎有效,但它不保留单词的顺序。另外,我觉得那是作弊,可能不是性能最好的选择。如果有 10 个前缀呢?100?我想知道是否有人有不同的感觉。

Slo*_*ens 8

正如上面的意见建议,你应该看一看的n-gram在Elasticsearch,尤其是边缘的n-gram。

我在这篇博文中为Qbox写了一篇关于使用ngrams 的介绍,但这里有一个你可以使用的快速示例。

这是一个索引定义,它将边缘 ngram 标记过滤器以及其他几个过滤器应用于自定义分析器(使用标准标记器)。

ES 2.0 中分析器的应用方式发生了一些变化。但是请注意,我用的是标准分析仪的"search_analyzer"。这是因为我不希望将搜索文本标记为 ngram,我希望它直接与索引标记匹配。有关详细信息的说明,请参阅博客文章。

无论如何,这是映射:

PUT /test_index
{
   "settings": {
      "analysis": {
         "analyzer": {
            "autocomplete": {
               "type": "custom",
               "tokenizer": "standard",
               "filter": [
                  "standard",
                  "stop",
                  "kstem",
                  "edgengram_filter"
               ]
            }
         },
         "filter": {
            "edgengram_filter": {
               "type": "edgeNGram",
               "min_gram": 2,
               "max_gram": 15
            }
         }
      }
   },
   "mappings": {
      "doc": {
         "properties": {
            "name": {
               "type": "string",
               "analyzer": "autocomplete",
               "search_analyzer": "standard"
            },
            "price":{
                "type": "integer"
            }
         }
      }
   }
}
Run Code Online (Sandbox Code Playgroud)

然后我索引了几个简单的文档:

POST /test_index/doc/_bulk
{"index":{"_id":1}}
{"name": "very cool shoes","price": 26}
{"index":{"_id":2}}
{"name": "great shampoo","price": 15}
{"index":{"_id":3}}
{"name": "shirt","price": 25}
Run Code Online (Sandbox Code Playgroud)

现在,以下查询将为我提供预期的自动完成结果:

POST /test_index/_search
{
   "query": {
      "match": {
         "name": {
            "query": "ver sh",
            "operator": "and"
         }
      }
   }
}
...
{
   "took": 4,
   "timed_out": false,
   "_shards": {
      "total": 5,
      "successful": 5,
      "failed": 0
   },
   "hits": {
      "total": 1,
      "max_score": 0.2169777,
      "hits": [
         {
            "_index": "test_index",
            "_type": "doc",
            "_id": "1",
            "_score": 0.2169777,
            "_source": {
               "name": "very cool shoes",
               "price": 26
            }
         }
      ]
   }
}
Run Code Online (Sandbox Code Playgroud)

这是我在示例中使用的所有代码:

http://sense.qbox.io/gist/c2ba05900d0749fa3b1ba516c66431ae1a9d5e61