【问题标题】:Elasticsearch: Find substring matchElasticsearch:查找子字符串匹配
【发布时间】:2014-06-08 06:15:30
【问题描述】:

我想同时执行完全单词匹配和部分单词/子字符串匹配。例如,如果我搜索“男士剃须刀”,那么我应该能够在结果中找到“男士剃须刀”。但如果我搜索“en's shaver”,那么我也应该能够在结果中找到“men's shaver”。 我使用以下设置和映射:

索引设置:

PUT /my_index
{
    "settings": {
        "number_of_shards": 1, 
        "analysis": {
            "filter": {
                "autocomplete_filter": { 
                    "type":     "edge_ngram",
                    "min_gram": 1,
                    "max_gram": 20
                }
            },
            "analyzer": {
                "autocomplete": {
                    "type":      "custom",
                    "tokenizer": "standard",
                    "filter": [
                        "lowercase",
                        "autocomplete_filter" 
                    ]
                }
            }
        }
    }
}

映射:

PUT /my_index/my_type/_mapping
{
    "my_type": {
        "properties": {
            "name": {
                "type":            "string",
                "index_analyzer":  "autocomplete", 
                "search_analyzer": "standard" 
            }
        }
    }
}

插入记录:

POST /my_index/my_type/_bulk
{ "index": { "_id": 1            }}
{ "name": "men's shaver" }
{ "index": { "_id": 2            }}
{ "name": "women's shaver" }

查询:

1.按精确词组匹配搜索 --> "men's"

POST /my_index/my_type/_search
{
    "query": {
        "match": {
            "name": "men's"
        }
    }
}

以上查询在返回结果中返回“男士剃须刀”。

2。按部分单词匹配搜索 --> "en's"

POST /my_index/my_type/_search
{
    "query": {
        "match": {
            "name": "en's"
        }
    }
}

以上查询不返回任何内容。

我也尝试过以下查询

POST /my_index/my_type/_search
{
    "query": {
        "wildcard": {
           "name": {
              "value": "%en's%"
           }
        }
    }
}

仍然没有得到任何东西。 我认为这是因为 Index 上的“edge_ngram”类型过滤器无法找到“部分单词/sbustring 匹配”。 我也尝试了“n-gram”类型的过滤器,但它大大减慢了搜索速度。

请建议我如何使用相同的索引设置同时实现精确词组匹配和部分词组匹配。

【问题讨论】:

    标签: autocomplete elasticsearch substring stringtokenizer n-gram


    【解决方案1】:

    要搜索部分字段匹配和完全匹配,如果您将字段定义为“未分析”或关键字(而不是文本),则效果会更好,然后使用通配符查询

    See also this.

    要使用通配符查询,请在要搜索的字符串的两端附加 *:

    POST /my_index/my_type/_search
    {
    "query": {
        "wildcard": {
           "name": {
              "value": "*en's*"
           }
        }
    }
    }
    

    要与不区分大小写一起使用,请使用带有小写过滤器和关键字标记器的自定义分析器。

    自定义分析器:

    "custom_analyzer": {
        "tokenizer": "keyword",
        "filter": ["lowercase"]
    }
    

    将搜索字符串设为小写

    如果搜索字符串为 AsD:将其更改为 *asd*

    【讨论】:

    • 谢谢。我现在可以搜索了。
    • 引用 ElasticSearch 的文档:“警告:允许在单词开头使用通配符(例如“*ing”)特别繁重,因为索引中的所有术语都需要检查”@987654322 @
    • 感谢您的提醒! @david_p
    • @david_p 的链接已损坏,但正如他所说,ElasticSearch 建议“避免使用以通配符开头的模式(例如,*foo 或作为正则表达式的 .*foo)” . elastic.co/guide/en/elasticsearch/guide/current/…
    • 它不适用于不区分大小写的情况。我们如何使用它来区分大小写?
    【解决方案2】:

    @BlackPOP 给出的答案会起作用,但它使用通配符方法,这不是首选,因为它存在性能问题,如果滥用会在 Elastic 集群中产生巨大的多米诺骨牌效应(性能问题)。

    我在部分搜索/自动完成方面写了详细的blog,涵盖了截至今天(2020 年 12 月)在 Elasticsearch 中可用的最新选项,并考虑了性能。更多权衡信息请参考this解答。

    恕我直言,更好的方法是根据用例使用自定义的n-gram tokenizer,它已经具有搜索词所需的令牌,因此它会更快,虽然它会有更大的索引大小,但你的大小是不是那么昂贵,并且通过更多地控制您希望子字符串搜索的工作方式,速度会更好。

    如果您在分词器设置中定义最小和最大克数时保守,也可以控制大小。

    【讨论】:

      【解决方案3】:

      通过搜索任何字符串或子字符串使用:

      query: {
          or: [{
            match_phrase_prefix: {
                  name: str
           }
          }, {
              match_phrase_prefix: {
                  surname: str
              }
          }]
      }
      

      使用 Elastic Search 进行愉快的编码......

      【讨论】:

      • 他不是在寻找匹配的前缀。
      猜你喜欢
      • 1970-01-01
      • 2016-07-01
      • 2018-08-03
      • 2016-05-15
      • 1970-01-01
      • 2015-09-02
      • 2018-08-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多