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

时间:2014-09-22 08:30:32

标签: search autocomplete elasticsearch

我想对QNMZ-1900

进行通配符查询

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

为防止出现这种情况,我使用了not_analyzed功能。

curl -XPUT 'localhost:9200/test-idx' -d '{
"mappings": {
    "doc": {
        "properties": {
            "foo" : {
                "type": "string",
                "index": "not_analyzed"
            }
        }
    }
}
}'

我在我的索引中添加了一些内容:

curl -XPUT 'localhost:9200/test-idx/doc/1' -d '{"foo": "QNMZ-1900"}'

刷新它:

curl -XPOST 'localhost:9200/test-idx/_refresh'

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

curl 'localhost:9200/test-idx/doc/_search?pretty=true' -d '{
"query": {
     "wildcard" : { "foo" : "QNMZ-19*" }
}

我的问题:

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

我试过了:

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'

但我的小写查询:

curl 'localhost:9200/test-idx/doc/_search?pretty=true' -d '{
"query": {
     "wildcard" : { "foo" : "qnmz-19*" }
}
}'

找不到任何东西。

如何解决?

2 个答案:

答案 0 :(得分:4)

一种解决方案是使用

定义自定义分析器
  • 一个keyword标记生成器(保持输入值不变,好像是not_analyzed
  • lowercase tokenfilter

我试过这个:

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

正如您所看到的那样使用_analyze端点:

GET test-idx/_analyze?analyzer=lowercase_hyphen&text=QNMZ-1900

只输出一个小写的标记但不在连字符上分割:

{
   "tokens": [
      {
         "token": "qnmz-1900",
         "start_offset": 0,
         "end_offset": 9,
         "type": "word",
         "position": 1
      }
   ]
}

然后,使用相同的查询:

POST test-idx/doc/_search
{
  "query": {
    "wildcard" : { "foo" : "qnmz-19*" }    
  }
}

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

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

但请注意,这样您只能使用小写值进行查询。 正如Andrei在评论中所述,具有值QNMZ-19*的相同查询不会返回任何内容。

原因可以在documentation中找到:在搜索时,不会分析该值。

答案 1 :(得分:0)

我在基于ES 6.1的宠物项目中检查了这个方法。如下所示的数据模型允许按预期搜索:

PUT test-idx
{
    "settings": {
        "analysis": {
            "analyzer": {
                "keylower": {
                    "type": "custom",
                    "tokenizer": "keyword",
                    "filter": ["lowercase"]
                }
            }
        }
    }
}

POST /test-idx/doc/_mapping
{
    "properties": {
        "foo": {
            "type": "text",
            "fields": {
                "raw": {
                    "type": "keyword"
                },
                "lowercase_foo": {
                    "type": "text",
                    "analyzer": "keylower"
                }
            }
        }
    }
}

PUT /test-idx/doc/1
{"foo": "QNMZ-1900"}

检查这两次搜索的结果。首先将重新打击一击。第二个将返回0次点击。

GET /test-idx/doc/_search
{
  "query": {
     "wildcard" : { "foo.lowercase_foo" : "qnmz-19*" }
  }
}

GET /test-idx/doc/_search
{
  "query": {
     "wildcard" : { "foo" : "qnmz-19*" }
  }
}

感谢@ThomasC的意见。请小心我的回答。我刚刚学习Elasticsearch。我不是这个数据库的专家。我不知道它是生产就绪的建议!