带连字符和小写过滤器的 Elasticsearch 通配符查询

ast*_*nic 3 search autocomplete elasticsearch

我想做一个通配符查询 QNMZ-1900

当我在文档中阅读并亲自尝试时,Elasticsearch 的标准标记器将连字符上的单词拆分,例如QNMZ-1900将拆分为QNMZ1900

为了防止这种行为,我正在使用该not_analyzed功能。

curl -XPUT 'localhost:9200/test-idx' -d '{
"mappings": {
    "doc": {
        "properties": {
            "foo" : {
                "type": "string",
                "index": "not_analyzed"
            }
        }
    }
}
}'
Run Code Online (Sandbox Code Playgroud)

我正在将一些内容放入我的索引中:

curl -XPUT 'localhost:9200/test-idx/doc/1' -d '{"foo": "QNMZ-1900"}'
Run Code Online (Sandbox Code Playgroud)

刷新它:

curl -XPOST 'localhost:9200/test-idx/_refresh'
Run Code Online (Sandbox Code Playgroud)

现在我可以使用通配符查询并找到QNMZ-1900

curl 'localhost:9200/test-idx/doc/_search?pretty=true' -d '{
"query": {
     "wildcard" : { "foo" : "QNMZ-19*" }
}
Run Code Online (Sandbox Code Playgroud)

我的问题:

如何使用小写搜索词运行通配符查询?

我试过了:

curl -XDELETE 'localhost:9200/test-idx'
curl -XPUT 'localhost:9200/test-idx' -d '{
"mappings": {
    "doc": {
        "properties": {
            "foo" : {
                "type": "string",
                "index": "not_analyzed",
                "filter": "lowercase"
            }
        }
    }
}
}'
curl -XPUT 'localhost:9200/test-idx/doc/1' -d '{"foo": "QNMZ-1900"}'
curl -XPOST 'localhost:9200/test-idx/_refresh'
Run Code Online (Sandbox Code Playgroud)

但我的小写查询:

curl 'localhost:9200/test-idx/doc/_search?pretty=true' -d '{
"query": {
     "wildcard" : { "foo" : "qnmz-19*" }
}
}'
Run Code Online (Sandbox Code Playgroud)

没有找到任何东西。

如何解决?

Tho*_*asC 7

一种解决方案是使用定义自定义分析器

  • 一个keyword标记器(它保持输入值原样,就好像它是not_analyzed
  • 一个lowercasetokenfilter

我试过这个:

POST test-idx
{
  "index":{
    "analysis":{
      "analyzer":{
        "lowercase_hyphen":{
          "type":"custom",
          "tokenizer":"keyword",
          "filter":["lowercase"]
        }
      }
    }
  }
}

PUT test-idx/doc/_mapping
{
  "doc":{
    "properties": {
        "foo" : {
          "type": "string",
          "analyzer": "lowercase_hyphen"
        }
    }      
  }
}

POST test-idx/doc
{
  "foo":"QNMZ-1900"
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,像这样使用 _analyze 端点:

GET test-idx/_analyze?analyzer=lowercase_hyphen&text=QNMZ-1900
Run Code Online (Sandbox Code Playgroud)

仅输出一个小写的标记,但不会在连字符上拆分:

{
   "tokens": [
      {
         "token": "qnmz-1900",
         "start_offset": 0,
         "end_offset": 9,
         "type": "word",
         "position": 1
      }
   ]
}
Run Code Online (Sandbox Code Playgroud)

然后,使用相同的查询:

POST test-idx/doc/_search
{
  "query": {
    "wildcard" : { "foo" : "qnmz-19*" }    
  }
}
Run Code Online (Sandbox Code Playgroud)

我有这个结果,这就是你想要的:

{
   "took": 66,
   "timed_out": false,
   "_shards": {
      "total": 5,
      "successful": 5,
      "failed": 0
   },
   "hits": {
      "total": 1,
      "max_score": 1,
      "hits": [
         {
            "_index": "test-idx",
            "_type": "doc",
            "_id": "wo1yanIjQGmvgfScMg4hyg",
            "_score": 1,
            "_source": {
               "foo": "QNMZ-1900"
            }
         }
      ]
   }
}
Run Code Online (Sandbox Code Playgroud)

但是,请注意,这将允许您仅使用小写的 value进行查询。正如安德烈在评论中所说,具有值的相同查询QNMZ-19*不会返回任何内容。

原因可以在文档中找到:在搜索时,没有分析该值。