在Elasticsearch的所有字段中按完全匹配搜索

时间:2019-07-06 13:00:26

标签: elasticsearch exact-match

假设我有3个文档,每个文档仅包含一个字段(但让我们想象还有更多,我们需要搜索所有字段)。

  1. 字段值为“第一秒”
  2. 字段值为“第二优先”
  3. 字段值为“第一,第二,第三”

这是一个可用于创建这三个文档的脚本:

# drop the index completely, use with care!
curl -iX DELETE 'http://localhost:9200/test'

curl -H 'content-type: application/json' -iX PUT 'http://localhost:9200/test/_doc/one' -d '{"name":"first second"}'
curl -H 'content-type: application/json' -iX PUT 'http://localhost:9200/test/_doc/two' -d '{"name":"second first"}'
curl -H 'content-type: application/json' -iX PUT 'http://localhost:9200/test/_doc/three' -d '{"name":"first second third"}'

我需要找到唯一一个在其一个字段中具有“第一秒”文本的文档(文档1)。

这是我尝试过的。

A。普通搜索:

curl -H 'Content-Type: application/json' -iX POST 'http://localhost:9200/test/_search' -d '{
  "query": {
    "query_string": {
      "query": "first second"
    }
  }
}'

返回所有3个文档

B。报价

curl -H 'Content-Type: application/json' -iX POST 'http://localhost:9200/test/_search' -d '{
  "query": {
    "query_string": {
      "query": "\"first second\""
    }
  }
}'

提供2个文档:1和3,因为它们都包含“第一第二”。

https://stackoverflow.com/a/28024714/7637120在这里,他们建议在建立索引时使用“关键字”分析器来分析字段,但是我想避免对映射进行任何自定义。

是否有可能避免它们而仍然只找到文档1?

2 个答案:

答案 0 :(得分:1)

是的,您可以通过将name映射类型声明为keyword来实现。解决问题的关键很简单-声明name映射type:keyword,然后就可以离开

为了证明这一点,我做了这些

1) created mapping with `keyword` for `name` field`
2) indexed the three documents
3) searched with a `match` query

映射

PUT so_test16
{
  "mappings": {
    "_doc":{
      "properties":{
        "name": {
          "type": "keyword"

        }
      }
    }
  }
}

为文档建立索引

POST /so_test16/_doc
{
    "id": 1,
    "name": "first second"
}
POST /so_test16/_doc
{
    "id": 2,
    "name": "second first"
}

POST /so_test16/_doc
{
    "id": 3,
    "name": "first second third"
}

查询

GET /so_test16/_search
{
  "query": {
    "match": {"name": "first second"}
  }
}

和结果

{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 1,
    "max_score" : 0.2876821,
    "hits" : [
      {
        "_index" : "so_test16",
        "_type" : "_doc",
        "_id" : "m1KXx2sB4TH56W1hdTF9",
        "_score" : 0.2876821,
        "_source" : {
          "id" : 1,
          "name" : "first second"
        }
      }
    ]
  }
}

添加第二个解决方案 (如果name不是keyword类型,而是text类型。这里只有fielddata:true才需要在name字段中添加)

映射

PUT so_test18
{

    "mappings" : {
      "_doc" : {
        "properties" : {
          "id" : {
            "type" : "long"
          },
          "name" : {
            "type" : "text",
            "fielddata": true
          }
        }
      }

  }
}

和搜索查询

GET /so_test18/_search
{
  "query": {
    "bool": {
      "must": [
        {"match_phrase": {"name": "first second"}}
      ],
      "filter": {

        "script": {
          "script": {
            "lang": "painless",
            "source": "doc['name'].values.length == 2"
          }
        }

      }
    }

  }
}

和回复

{
  "took" : 3,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 1,
    "max_score" : 0.3971361,
    "hits" : [
      {
        "_index" : "so_test18",
        "_type" : "_doc",
        "_id" : "o1JryGsB4TH56W1hhzGT",
        "_score" : 0.3971361,
        "_source" : {
          "id" : 1,
          "name" : "first second"
        }
      }
    ]
  }
}

答案 1 :(得分:1)

在Elasticsearch 7.1.0中,即使您没有创建特殊的映射,似乎也可以使用keyword分析器。至少我没有,以下查询可以满足我的需求:

curl -H 'Content-Type: application/json' -iX POST 'http://localhost:9200/test/_search' -d '{
  "query": {
    "query_string": {
      "query": "first second",
      "analyzer": "keyword"
    }
  }
}'