【问题标题】:How to match multiple words as token prefixes如何匹配多个单词作为标记前缀
【发布时间】:2015-11-11 11:52:13
【问题描述】:

我想要查询像“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"
                }
              }
            }
          }
        }
      }
    }
  }
}

我一直在搜索词组:

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"
            }
          }
        }
      ]
    }
  }
}

当事情真正开始那个短语时,这很好用,但现在我想对查询进行标记并将每个标记视为前缀。

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

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

POST test/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "prefix": {
            "answer.text.stemmed": "jan"
          }
        },
        {
          "prefix": {
            "answer.text.stemmed": "do"
          }
        }
      ]
    }
  }
}

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

【问题讨论】:

  • @keety 这对我没有帮助。我显然是一个新手,需要的不仅仅是指向稀疏文档页面的链接。不过还是谢谢。

标签: elasticsearch


【解决方案1】:

正如上面的评论所暗示的,你应该看看 Elasticsearch 中的ngrams,尤其是edge ngrams

我在this blog post 中为Qbox 编写了使用ngram 的介绍,但这里有一个简单的示例,您可以使用。

这是一个将edge ngram token filter 以及其他几个过滤器应用于自定义分析器的索引定义(使用standard tokenizer)。

在 ES 2.0 中analyzers are applied 的方式发生了一些变化。但请注意,我将standard analyzer 用于"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"
            }
         }
      }
   }
}

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

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}

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

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
            }
         }
      ]
   }
}

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

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

【讨论】:

  • 非常感谢。你太棒了,也是我 5 年前加入这个社区的原因。请继续努力,努力工作! :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-10-21
  • 1970-01-01
  • 2011-05-19
  • 2015-08-16
  • 2013-04-17
  • 2023-01-05
  • 1970-01-01
相关资源
最近更新 更多