在Elasticsearch中查找与整个查询匹配的文档

时间:2018-11-30 10:43:16

标签: elasticsearch search

我想在ElasticSearch中编写查询,该查询提供的结果包含搜索查询中的所有单词,但不仅包含完整单词,还包含子单词。例如,如果我的文档具有以下值:

{
"first_name":"didier",
"last_name":"drogba"
}

并且我搜索“ didi dro”,应该返回此文档。如果我搜索“ david drogba”,则文档应被忽略,因为它不包含单词“ david”,甚至不包含子单词。 我使用ngram tokenizer进行了尝试,但无法实现我想要的功能。

我创建的索引

PUT doctors
{
  "settings": {
    "analysis": {
      "analyzer": {
        "my_analyzer": {
          "tokenizer": "my_tokenizer"
        }
      },
      "tokenizer": {
        "my_tokenizer": {
          "type": "ngram"
        }
      }
    }
  }
}

然后添加映射

put doctors/_doc/_mapping 
{
  "properties": {
    "first_name": {
      "type": "text",
      "analyzer": "my_analyzer"
    },
    "last_name": {
      "type": "text",
      "analyzer": "my_analyzer"
    }
  }
}

添加一些文档

post doctors/_doc/1
{
  "first_name": "dito",
  "last_name": "janelidze",
  "specialism": "oftalmologist",
  "location_name":"evex saburtalo clinic",
  "brand": "Evex",
  "address":"kavtaradze street N21"
}

我的搜索查询如下

get doctors/_doc/_search
{
  "query": {
    "multi_match": {
        "query": "david jane",
        "fields": ["first_name", "last_name"]
    }
  }
}

它给了我插入的文档,但我不需要它,因为它不包含单词“ david”

2 个答案:

答案 0 :(得分:1)

+1表示每个单词的“ and”运算符。使用此功能,对我有用(也可以用于自动完成功能)。

settings:
    analysis": {
          "filter": {
            "name_ngrams": {
              "max_gram": "20",
              "type": "edgeNGram",
              "min_gram": "1",
              "side": "front"
            }
          },
          "analyzer": {
            "partial_name": {
              "type": "custom",
              "filter": [
                "lowercase",
                "name_ngrams",
                "standard",
                "asciifolding"
              ],
              "tokenizer": "standard"
            },
            "full_name": {
              "type": "custom",
              "filter": [
                "standard",
                "lowercase",
                "asciifolding"
              ],
              "tokenizer": "standard"
            }
          }


mapping:

    "first_name": {

        "type": "text",
        "index_analyzer": "partial_name",
        "search_analyzer": "full_name"

    },
    "last_name": {

        "type": "text",
        "index_analyzer": "partial_name",
        "search_analyzer": "full_name"

    },

答案 1 :(得分:1)

第1点:映射更改

N-Gram tokenizer将根据输入单词构造指定 length 个单词。 长度 在映射中被指定为min_grammax_gram,如果您未指定,则默认为1,分别2

我已经分别更新了min_gram:3max_gram:5所提供的映射。

然后N-Gram Tokenizer将创建令牌,例如对于didier,它们将是did, idi, die, ier, didi, idie, dier, didie, idier,最终将它们存储在反向索引中。

将默认1和2分别设置为min_grammax_gram,请注意didierdavidid作为公共子词,这就是为什么它们返回。


映射

PUT doctors
{
  "settings": {
    "analysis": {
      "analyzer": {
        "my_analyzer": {
          "tokenizer": "my_tokenizer"
        }
      },
      "tokenizer": {
        "my_tokenizer": {
          "type": "ngram",
          "min_gram": 3,
          "max_gram": 6,
        }
      }
    }
  }
}

第2点:查询更改

也就是说,尽管更改了映射,但是如果您的查询字符串使用的是david jane,它将在david or janefirst_name中搜索last_name。这意味着文档dito janelidze仍将返回(但得分比具有david jane的得分更低)

使用运算符AND将在david AND janefirst_name中以last_name进行搜索,这不是您想要的。

相反,您可以使用以下布尔查询创建另一个名为name的字段,将first_namelast_name的值复制到其中使用copy_to字段,然后使用该字段进行搜索。


查询

POST <your_index_name>/_search
{
  "query": {
    "bool":{
      "must": [
        {
          "match": {
            "first_name": "david"
          }
        },
        {
          "match": {
            "last_name": "jane"
          }
        }
      ]
    }
  }
}

不幸的是,由于所需的更改在映射级别,因此您将需要删除,重新创建索引并再次摄取文档。

希望这会有所帮助!