首页 > 解决方案 > 使用来自 elasticsearch 的通配符搜索完整和部分文本值

问题描述

我有下面的简单表格,其中包含来自 elasticsearch 的标题和代码列,如下所示

{ title: 'test1', code: 'ZjS3d3k8z',... },
{ title: 'test2 with more words', code: 'AjS3d2k1z',... }

我正在尝试使用通配符过滤标题和代码,如下所示,

{
  "sort": [
    {
      "creation_date": {
        "order": "desc"
      }
    },
    "_score"
  ],
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "account_id": 100
          }
        }
      ],
      "should": [
        {
          "wildcard": {
            "code": "?test2 with"
          }
        },
        {
          "wildcard": {
            "title": "*test2 with*"
          }
        }
      ],
      "minimum_number_should_match": 1
    }
  }
}

上述查询适用于预期结果/失败,在以下情况下没有结果

> 'test1' <---- works(return expected result) when i try to search single word
> 'test2' <---- works(return expected result) when i try to search single word
> 'test2 with'<---- fails(return empty result) when i try to search more than one word with space'
> 'test2 with more words' <---- fails(return empty result) when i try to search full title

当我尝试如下搜索代码时,它总是返回空结果!!!

"should": [
        {
          "wildcard": {
            "code": "?ZjS3d3k8z"
          }
        },
        {
          "wildcard": {
            "title": "*ZjS3d3k8z*"
          }
        }
      ]

我想使用弹性搜索从数百万条记录中搜索具有部分/全部价值的标题/代码。好心提醒。

标签: javascriptnode.jselasticsearchnosql

解决方案


对于通配符,在 "keyword" 字段而不是 "text" 上执行搜索。对于文本数据类型,分析字符串,分解为标记,同时按原样存储关键字字段。"test2 with more words" 存储为 ["test2","with","more","words"] 并且您的通配符输入与这些标记匹配,因此不返回任何文档。

{
  "query": {
    "bool": {
      "should": [
        {
          "wildcard": {
            "code.keyword": "*test2 with*"
          }
        },
        {
          "wildcard": {
            "title.keyword": "*test2 with*"
          }
        }
      ],
      "minimum_should_match": 1
    }
  }
}

使用动态模板创建的映射具有每种文本类型的关键字子字段。如果您已显式创建映射,则需要添加关键字子字段

"title": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "text"
          }
        }
      }

外卡性能较差,有更好的选择。

  1. Match/Match_phrase/Match_phrase_prefix

如果您正在搜索诸如“test2 with”之类的整个令牌。您可以简单地进行匹配查询,将返回所有包含标记“test2”和“with”的文档

"should": [
        {
          "match": {
            "code": {
              "query": "test2 with",
              "operator": "and"
            }
          }
        },
        {
          "match": {
            "title": {
              "query": "test2 with",
              "operator": "and"
            }
          }
        }
      ]

如果令牌的顺序很重要,您可以使用 match_phrase。

如果要搜索部分标记,请使用 match_phrase_prefix。前缀匹配仅在搜索输入 ex 中的最后一个标记上完成。“测试2 w”

  1. 边 N 克

每当遇到指定字符列表中的一个时,edge_ngram 标记器首先将文本分解为单词,然后它发出每个单词的 N-gram,其中 N-gram 的开头锚定到单词的开头。

{
  "settings": {
    "analysis": {
      "analyzer": {
        "my_analyzer": {
          "tokenizer": "my_tokenizer"
        }
      },
      "tokenizer": {
        "my_tokenizer": {
          "type": "edge_ngram",
          "min_gram": 2,
          "max_gram": 10,
          "token_chars": [
            "letter",
            "digit"
          ]
        }
      }
    }
  }
}

生成的令牌:

"tokens" : [
    {
      "token" : "te",
      "start_offset" : 0,
      "end_offset" : 2,
      "type" : "word",
      "position" : 0
    },
    {
      "token" : "tes",
      "start_offset" : 0,
      "end_offset" : 3,
      "type" : "word",
      "position" : 1
    },
    {
      "token" : "test",
      "start_offset" : 0,
      "end_offset" : 4,
      "type" : "word",
      "position" : 2
    },
    {
      "token" : "test2",
      "start_offset" : 0,
      "end_offset" : 5,
      "type" : "word",
      "position" : 3
    },
    {
      "token" : "wi",
      "start_offset" : 6,
      "end_offset" : 8,
      "type" : "word",
      "position" : 4
    },
    {
      "token" : "wit",
      "start_offset" : 6,
      "end_offset" : 9,
      "type" : "word",
      "position" : 5
    },
    {
      "token" : "with",
      "start_offset" : 6,
      "end_offset" : 10,
      "type" : "word",
      "position" : 6
    }
  ]

这将让您执行像“tes wit”这样的搜索,即任何标记都可以是部分的,不像 match_phrase_prefix 只对最后一个标记进行前缀搜索

  1. N 克

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

N-gram 就像一个在单词上移动的滑动窗口 - 指定长度的连续字符序列

即使在中间“est”匹配测试中,您也可以搜索部分标记

  1. 建议 者他们在您键入时提供搜索功能

您可以根据您的要求选择其中任何一个


推荐阅读