首页 > 解决方案 > 是否有任何解决方案可以在弹性搜索中搜索确切的单词和包含单词

问题描述

index: process.env.elasticSearchIndexName,
      body: {
        query: {
          bool: {
            must: [
              {
                match_phrase: {
                  title: `${searchKey}`,
                },
              },
            ],
          },
        },
      },
      from: (page || constants.pager.page),
      size: (limit || constants.pager.limit),

我正在使用上述方法,但问题在于它仅在整个文本中搜索完全匹配的单词。它无法搜索包含单词.. 例如,如果 title = "sweatshirt" 而不是我输入单词 "shirt" 它应该得到结果,但目前使用上述方法没有得到结果

标签: node.jselasticsearch

解决方案


标准分析器(如果未指定默认分析器)会破坏标记中的文本。对于句子“这是一个测试”,生成的标记是 [this,is,a,test] Match_pharse 查询使用与索引分析器相同的分析器打破标记中的文本,并返回 1. 包含所有标记 2. 标记以相同顺序出现的文档。

由于您的文本是运动衫,因此倒排索引中有一个标记“运动衫”,它与运动衫或衬衫都不匹配

NGram 分词器

每当遇到指定字符列表中的一个时,ngram 标记器首先将文本分解为单词,然后发出指定长度的每个单词的 N-gram

映射

PUT my_index
{
  "settings": {
    "analysis": {
      "analyzer": {
        "my_analyzer": {
          "tokenizer": "my_tokenizer"
        }
      },
      "tokenizer": {
        "my_tokenizer": {
          "type": "ngram",
          "min_gram": 3,
          "max_gram": 3,
          "token_chars": [
            "letter",
            "digit"
          ]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "text":{
        "type": "text",
        "analyzer": "my_analyzer"
      }
    }
  }
}

询问:

{
  "query": {
    "match": {
      "text": "shirt"
    }
  }
}

如果您将运行 _analyze 查询

GET my_index/_analyze
{
  "text": ["sweatshirt"],
  "analyzer": "my_analyzer"
}

您将看到为文本运动衫生成了下面的令牌。可以使用 min_gram 和 max_gram 调整令牌的大小

{
  "tokens" : [
    {
      "token" : "swe",
      "start_offset" : 0,
      "end_offset" : 3,
      "type" : "word",
      "position" : 0
    },
    {
      "token" : "wea",
      "start_offset" : 1,
      "end_offset" : 4,
      "type" : "word",
      "position" : 1
    },
    {
      "token" : "eat",
      "start_offset" : 2,
      "end_offset" : 5,
      "type" : "word",
      "position" : 2
    },
    {
      "token" : "ats",
      "start_offset" : 3,
      "end_offset" : 6,
      "type" : "word",
      "position" : 3
    },
    {
      "token" : "tsh",
      "start_offset" : 4,
      "end_offset" : 7,
      "type" : "word",
      "position" : 4
    },
    {
      "token" : "shi",
      "start_offset" : 5,
      "end_offset" : 8,
      "type" : "word",
      "position" : 5
    },
    {
      "token" : "hir",
      "start_offset" : 6,
      "end_offset" : 9,
      "type" : "word",
      "position" : 6
    },
    {
      "token" : "irt",
      "start_offset" : 7,
      "end_offset" : 10,
      "type" : "word",
      "position" : 7
    }
  ]
}

警告:Ngrams 会增加倒排索引的大小,因此请使用适当的 min_gram 和 max_gram 值

另一种选择是使用通配符查询。对于通配符,必须扫描所有文档以检查文本是否与模式匹配。它们的性能低下。在 not_analyzed 字段上使用通配符搜索时,如果您想包含空格 ex text.keyword

{
  "query": {
    "wildcard": {
      "text": {
        "value": "*shirt*"
      }
    }
  }
}

推荐阅读