[Elasticsearch] 部分匹配 (一) - 前缀查询

本文深入探讨了Elasticsearch中的部分匹配技术,包括如何使用前缀查询、wildcard查询和正则表达式查询来匹配结构化数据,如邮政编码、产品序列号等。详细解释了这些查询在不同场景下的应用,以及如何优化查询性能。

部分匹配(Partial Matching)

敏锐的读者可能已经发现到眼下为止,介绍的查询都是在整个词条层面进行操作的。

匹配的最小单元必须是一个词条。你仅仅能找到存在于倒排索引(Inverted Index)中的词条。

可是假设你想匹配词条的一部分,而不是整个词条呢?部分匹配(Partial Matching)同意用户指定词条的一部分然后找到含有该部分的不论什么单词。

匹配词条一部分这一需求在全文搜索引擎领域比你想象的要不那么常见。假设你有SQL的背景。你可能有过使用以下的SQL语句来实现一个简单的全文搜索功能的经历:

WHERE text LIKE "*quick*"
      AND text LIKE "*brown*"
      AND text LIKE "*fox*"

当然,通过ES我们能够借助分析过程(Analysis Process)和倒排索引来避免这样的"蛮力"技术。

为了同一时候匹配"fox"和"foxes",我们能够简单地使用一个词干提取器,然后将词干进行索引。这样就没有必要进行部分匹配了。

即便如此,在某些场合下部分匹配还是有作用的。常见的用例比方:

  • 匹配邮政编码,产品序列号。或者其他以某个特定前缀开头的或者可以匹配通配符甚至正則表達式的not_analyzed值。
  • 即时搜索(Search-as-you-type) - 在用户完毕搜索词条的输入前就展示最有可能的结果。

  • 匹配德语或者荷兰语这一类语言,它们韩哟长复合单词。比方Weltgesundheitsorganisation(World Health Organization)。

我们以针对精确值not_analyzed字段的前缀匹配開始。介绍部分匹配的技术。



邮政编码和结构化数据

我们以英国的邮政编码来说明怎样在结构化数据上使用部分匹配。

英国邮政编码是一个定义清晰的结构。比方,W1V 3DG这个邮政编码能够被分解成下面几个部分:

  • W1V:这个部分表明了邮政地域和地区(Postal Area and District):
    • W 表明了地域(Area)。使用一个或者两个字母。
    • 1V 表明了地区(District)。使用一个或者两个数字,可能尾随一个字母。
  • 3DG:该部分表明了街道或者建筑:
    • 3 表明了区域(Sector)。使用一个数字。

    • DG 表明了单元,使用两个字母。

如果我们将邮政编码索引为精确值的not_analyzed字段,因此我们能够创建例如以下索引:

PUT /my_index
{
    "mappings": {
        "address": {
            "properties": {
                "postcode": {
                    "type":  "string",
                    "index": "not_analyzed"
                }
            }
        }
    }
}

然后索引一些邮政编码:

PUT /my_index/address/1
{ "postcode": "W1V 3DG" }

PUT /my_index/address/2
{ "postcode": "W2F 8HW" }

PUT /my_index/address/3
{ "postcode": "W1F 7HW" }

PUT /my_index/address/4
{ "postcode": "WC1N 1LZ" }

PUT /my_index/address/5
{ "postcode": "SW5 0BE" }

如今我们的数据就准备就绪了。



前缀查询(Prefix Query)

我们能够通过一个简单的prefix查询来得到全部以W1开头的邮政编码:

GET /my_index/address/_search
{
    "query": {
        "prefix": {
            "postcode": "W1"
        }
    }
}

prefix查询是一个工作在词条级别的低级查询。它不会在搜索前对查询字符串进行解析。它如果用户会传入一个须要查询的精确前缀。

TIP

默认情况下。prefix查询不会计算相关度分值。它仅仅是进行文档匹配,匹配的文档的分值为1。

事实上,相比查询它更像一个过滤器。

prefix查询和prefix过滤器的唯一差别在于过滤器能够被缓存。

之前。我们提到过"你仅仅能找到存在于倒排索引中的词条"。可是对于这些邮政编码我们并没有进行不论什么特殊处理;每一个邮政编码仅仅是被当做精确值被简单地索引。那么prefix查询是怎样工作的呢?

记住倒排索引是由唯一词条得有序列表构成的(此种情况下。即邮政编码)。对于每一个词条。它会列举全部含有该词条的文档ID。对于我们的演示样例文档,倒排索引例如以下所看到的:

Term:          Doc IDs:
-------------------------
"SW5 0BE"    |  5
"W1F 7HW"    |  3
"W1V 3DG"    |  1
"W2F 8HW"    |  2
"WC1N 1LZ"   |  4
-------------------------

为了支持前缀匹配。查询会运行下面的步骤:

  1. 遍历词条列表并找到以W1开头的词条。

  2. 收集相应的文档ID。
  3. 移动到下一个词条。

  4. 假设该词条也以W1开头。那么反复步骤2;否则结束操作。

虽然以上的步骤对于我们的小样例而言能非常好地工作,想象一下当倒排索引含有一百万个以W1开头的邮政编码时的情景,prefix查询须要訪问一百万个词条来得到结果。

而前缀越短,就意味着须要訪问越多的词条。

假设我们查询前缀为W,而不是W1的词条。可能会匹配多达一千万个词条。

注意

prefix查询和过滤器对于即时(Ad-hoc)的前缀匹配是实用处的,可是在使用它们的时候须要小心。

对于拥有少量词条的字段能够任意地使用。可是它们的扩展性较差,可能会让你的集群承受过多的压力。

能够通过使用一个较长的前缀来限制它们对于集群的影响。这能够降低须要訪问的词条的数量。

在本章的后面部分,我们将推出一个解决方案,使指数在更有效的前缀匹配。但首先,让我们来看看两个相关查询:wildcard以及regexp询。


<think>好的,我现在需要解决用户关于Elasticsearch中match_phrase_prefix查询的使用方法和示例的问题。用户已经提供了之前的回答和些引用内容,我需要整合这些信息,确保回答准确且符合用户的需求。 首先,我需要回顾用户之前的问题和回答。用户之前询问了match_phrase_prefix的详解与分词处理,我的回答包括了核心特性、关键参数、分词处理、示例以及注意事项。现在用户进步询问使用方法及示例,可能希望得到更具体的指导,或者实际操作的步骤。 接下来,用户提供的引用内容提到了term、match、match_phrase、match_phrase_prefix的区别,以及分词器的选择建议。特别是引用[3]提到,使用ik_max_word分词器可以覆盖更多分词结果,而match_phrase_prefix适合在短语匹配时防止遗漏。这些信息需要整合到回答中,确保用户理解不同查询类型的适用场景。 用户当前的问题集中在match_phrase_prefix的使用方法和示例。我需要确保回答结构清晰,分步骤说明,并给出具体的示例代码,同时比较与其他查询的区别,帮助用户理解何时选择该查询。 同时,用户可能存在的深层需求是正确配置查询,避免性能问题,或者处理分词不致的情况。因此,在注意事项部分需要强调分词器致性、性能优化参数如max_expansions,以及替代方案如edge_ngram或completion suggester。 在整理回答时,我需要参考之前的回答,确保不重复但补充更多细节,比如更具体的示例、参数解释和实际应用场景。此外,用户可能希望了解如何验证分词结果,因此需要包括使用Analyze API和Explain API的方法。 最后,生成的相关问题需要引导用户进步探索,比如优化性能、与其他查询对比、监控影响等,这样有助于他们深入学习。 现在需要确保回答符合用户的要求:结构清晰,分步骤解决,示例正确,注意事项明确,并包含相关问题。同时,使用正确的中文表达,避免术语错误,并引用提供的参考资料。</think>### Elasticsearch `match_phrase_prefix` 前缀匹配查询详解 --- #### 、`match_phrase_prefix` 的核心功能 `match_phrase_prefix` 是种结合短语匹配前缀匹配查询类型,适合以下场景: - **用户输入未完成时的实时补全**(如搜索框输入“大数”时匹配大数据分析”) - **模糊匹配短语的最后个词**(如“机器学”匹配“机器学习算法”) - **需保持分词顺序但允许最后个词不完整**的检索需求[^1][^3]。 --- #### 二、基本使用方法与语法 ##### 1. **查询语法模板** ```json GET /索引名/_search { "query": { "match_phrase_prefix": { "字段名": { "query": "搜索短语", "max_expansions": 50, // 控制最后个词的前缀扩展数量 "slop": 0, // 允许分词间隔(默认0,需严格顺序) "analyzer": "ik_smart" // 指定分词器(需与字段定义致) } } } } ``` ##### 2. **参数说明** | 参数 | 作用 | 默认值 | 示例值 | |-----------------|----------------------------------------------------------------------|--------|-------------| | `query` | 待搜索的短语,必须包含至少两个分词(否则退化为前缀查询) | 必填 | "机器学习算" | | `max_expansions`| 控制最后个词的前缀扩展数量,避免内存过载 | 50 | 20 | | `slop` | 允许前 N-1 个分词之间的间隔(如 `slop=1` 可容忍插入个无关词) | 0 | 2 | | `analyzer` | 指定查询时使用的分词器(需与字段定义的分词器致) | 默认 | "ik_max_word" | --- #### 三、典型使用场景与示例 ##### 示例1:自动补全搜索 **需求**:用户输入“大数”时,匹配大数据分析”“大数据平台”等文档。 **查询配置**: ```json GET /articles/_search { "query": { "match_phrase_prefix": { "title": { "query": "大数", "max_expansions": 10, "analyzer": "ik_max_word" } } } } ``` **分词结果**:`["大", "数"]` **匹配逻辑**: - 标题字段必须包含顺序连续的“大”和“数” - 后续词项需以“数”开头(如“数据”“数学”) ##### 示例2:模糊短语匹配 **需求**:搜索“机器学 算法”匹配“机器学习算法”。 **查询配置**: ```json GET /tech_docs/_search { "query": { "match_phrase_prefix": { "content": { "query": "机器学 算", "slop": 1, "analyzer": "ik_smart" } } } } ``` **分词结果**:`["机器学", "算"]` **匹配逻辑**: - 允许“机器学”和“算”之间有1个词的间隔(`slop=1`) - 最后个词“算”匹配前缀(如“算法”“算术”) --- #### 四、与其他查询的对比 | 查询类型 | 特点 | 适用场景 | |------------------------|----------------------------------------------------------------------|------------------------------| | `term` | 精确匹配未分词的字段 | 关键字、枚举值查询 | | `match` | 分词后匹配任意词项(忽略顺序) | 全文搜索、模糊匹配 | | `match_phrase` | 严格匹配分词顺序且无间隔 | 精确短语搜索(如“红色毛衣”) | | `match_phrase_prefix` | 前N-1个词严格顺序,最后个词前缀匹配 | 自动补全、未完成短语搜索 | | `wildcard` | 通配符匹配(性能低) | 已知部分字符的模糊匹配 | --- #### 五、关键注意事项 1. **分词器致性** - 字段定义时若使用 `ik_max_word`,查询时也必须指定相同的分词器,否则可能导致分词不致而匹配失败[^3]。 - 验证方法:通过 `Analyze API` 检查分词结果: ```json GET /_analyze { "analyzer": "ik_max_word", "text": "机器学习算" } ``` 2. **性能优化** - `max_expansions` 需合理设置(通常10-50),避免生成过多词项拖慢查询[^3]。 - 避免单字符前缀(如“a*”),可能触发海量扩展。 3. **替代方案选择** - **高频前缀场景**:使用 `edge_ngram` 分词器 + `term` 查询(性能更优)。 - **实时补全**:优先使用 `completion suggester`(专为补全设计,响应更快)。 --- #### 六、完整示例:从配置到验证 **步骤1:创建索引并指定分词器** ```json PUT /tech_docs { "mappings": { "properties": { "content": { "type": "text", "analyzer": "ik_max_word" } } } } ``` **步骤2:插入测试数据** ```json POST /tech_docs/_doc/1 { "content": "机器学习算法在数据分析中的应用" } ``` **步骤3:执行 `match_phrase_prefix` 查询** ```json GET /tech_docs/_search { "query": { "match_phrase_prefix": { "content": { "query": "机器学 算", "analyzer": "ik_max_word" } } } } ``` **步骤4:验证匹配结果** ```json { "hits": { "hits": [ { "_source": { "content": "机器学习算法在数据分析中的应用" } } ] } } ``` --- ### 相关问题 1. **如何通过 `edge_ngram` 分词器实现高性能前缀匹配?** 2. **`match_phrase_prefix` 与 `completion suggester` 在自动补全场景中的性能差异如何?** 3. **当 `match_phrase_prefix` 查询返回空结果时,如何进行分词问题诊断?** [^1]: Elasticsearch 查询类型对比(term/match/phrase) [^3]: match_phrase_prefix 的实际应用与分词器选择建议
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值