在 Elasticsearch 中实现自动完成功能 1:Prefix queries

news2025/3/1 9:22:37

自动完成与搜索功能不同 - 我们应该在用户键入下一个字符后立即更新自动完成选项,每秒都会访问数据库,过滤数百万条记录,而不会导致任何性能下降!

Elasticsearch 是一种可以轻松实现此类功能的技术,它是一种基于 Apache Lucene 库构建的搜索和分析引擎。 Elasticsearch 具有分布式、多租户架构,具有内置路由和重新平衡功能,使其易于扩展。 它是一种广泛使用的数据存储,用于存储、搜索和分析大量数据。

在这个由三部分组成的博客文章系列中,我将详细介绍如何使用 Elasticsearch 中提供的各种选项来实现自动完成功能。 在第一部分(即这篇文章)中,我们将讨论前缀查询 - prefix queries。 在第二部分中,我们将了解 n-grams,在最后部分中,我们将讨论 complete suggesters。

出于示例目的,我们将使用存储电影数据的索引。 为了简单起见,title 将是该索引中唯一存在的属性。 由于 Elasticsearch 为其操作公开了 REST 接口,因此你可以使用任何基于 REST 的工具与其进行通信。

本系列假设你对 Elasticsearch 有基本的了解。 如果你是 Elasticsearch 的新手,我强烈建议你阅读 “Elastic:开发者上手指南”。

那么让我们开始吧?

前缀查询 - Prefix queries

前缀查询是 Elasticsearch 中自动完成实现的最简单形式。 我们在存储字段时不做任何特殊的事情,大部分工作都是在查询时完成的。 该字段被索引(存储!)为一个简单的文本/关键字字段,并且允许我们根据传递的前缀匹配文档的查询用于查询它。

让我们创建一个索引来运行前缀查询:

PUT /movies
{
  "mappings": {
    "properties": {
      "title": {
        "type": "keyword",
        "fields": {
          "analyzed_title": {
            "type": "text"
          }
        }
      }
    }
  }
}

创建索引时,我们需要提供映射,指示我们打算存储的数据类型。 出于以下示例的目的,title 被映射为 keyword 字段,也被映射为支持全文查询的文本字段。 使用 Elasticsearch 的多字段功能可以将一个字段映射为多种类型。

keyword 字段和 text 字段之间的主要区别在于关键字字段不被分析,即我们传递到关键字字段的数据按原样存储。 对文本字段进行分析,即分词化、可能进行转换(例如小写、词干等),并存储在倒排索引中。 倒排索引是一种数据结构,用于存储从术语到它们出现的文档位置的映射,从而实现高效的全文搜索。有关 keyword 和 text 类型的区别,请详细参阅文档 “Elasticsearch:Text vs. Keyword - 它们之间的差异以及它们的行为方式”。

为了测试如何分析我们的数据,我们可以使用 _analyze API。 让我们看看我们的主标题字段将如何分析:

GET /movies/_analyze
{
  "text": "Chamber of Secrets",
  "field": "title"
}

上面命令的响应为:

{
  "tokens": [
    {
      "token": "Chamber of Secrets",
      "start_offset": 0,
      "end_offset": 18,
      "type": "word",
      "position": 0
    }
  ]
}

因此,它只返回一个 token。 为什么? 没错,就是因为它是关键字字段! 让我们测试一下我们 analyzed_title 的表现:

GET /movies/_analyze
{
  "text": "Chamber of Secrets",
  "field": "title.analyzed_title"
}

上面命令的响应为:

{
  "tokens": [
    {
      "token": "chamber",
      "start_offset": 0,
      "end_offset": 7,
      "type": "<ALPHANUM>",
      "position": 0
    },
    {
      "token": "of",
      "start_offset": 8,
      "end_offset": 10,
      "type": "<ALPHANUM>",
      "position": 1
    },
    {
      "token": "secrets",
      "start_offset": 11,
      "end_offset": 18,
      "type": "<ALPHANUM>",
      "position": 2
    }
  ]
}

正如所料,它被分解为三个 token。 此外,token 是小写的。 这是为什么? 因为,即使我们不指定任何分析器,默认的标准分析器也会应用于执行基于语法的标记化的文本字段,并且还将这些标记小写。 文本分析是一种高度可配置的过程,由一个或多个字符过滤器、分词器以及一个或多个在管道中运行的分词过滤器组成。 我们可以创建自己的分析器,也可以定制内置分析器。有关分词器的详细介绍,请阅读文章 “Elasticsearch: analyzer”。

让我们将一些哈利波特电影添加到我们的索引中,即让我们索引一些文档:

POST /movies/_doc
{
  "title": "Harry Potter and the Chamber of Secrets"
}

POST /movies/_doc
{
  "title": "Harry Potter and the Prisoner of Azkaban"
}

让我们尝试使用前缀查询来查询我们的主 title 字段(关键字)。 前缀查询是术语级别查询的一种,用于查询非分析字段。 我们将尝试两个不同的请求 - 第一个请求使用 title 中第一个单词的前缀,另一个请求使用标题中第二个单词的前缀:

GET /movies/_search?filter_path=**.hits
{
  "query": {
    "prefix": {
      "title": "Harr"
    }
  }
}

 上面的响应为:

{
  "hits": {
    "hits": [
      {
        "_index": "movies",
        "_id": "er9oHIsByaLf0EuTh81O",
        "_score": 1,
        "_source": {
          "title": "Harry Potter and the Chamber of Secrets"
        }
      },
      {
        "_index": "movies",
        "_id": "e79oHIsByaLf0EuTjc3H",
        "_score": 1,
        "_source": {
          "title": "Harry Potter and the Prisoner of Azkaban"
        }
      }
    ]
  }
}

我们做另外一个查询:

GET /movies/_search?filter_path=**.hits
{
  "query": {
    "prefix": {
      "title": "Pott"
    }
  }
}

上述查询返回:

{
  "hits": {
    "hits": []
  }
}

也即没有任何的结果。

tilte 是关键字字段,我们必须提供具有正确大小写的前缀。 如果我们在查询中传递 “harr”,它将不匹配。 第一个请求按预期返回上面索引的两个文档。 但第二个请求不会返回任何内容。 这是因为这个查询不支持中缀(在 title 中间匹配)匹配。

如果我们想在 title 内进行匹配,我们应该使用 match_phrase_prefix - 一种用于在分析的文本字段上进行前缀匹配的查询类型:

GET /movies/_search?filter_path=**.hits
{
  "query": {
    "match_phrase_prefix": {
      "title.analyzed_title": {
        "query": "pott"
      }
    }
  }
}

上述命令返回的结果为:

{
  "hits": {
    "hits": [
      {
        "_index": "movies",
        "_id": "er9oHIsByaLf0EuTh81O",
        "_score": 0.18232156,
        "_source": {
          "title": "Harry Potter and the Chamber of Secrets"
        }
      },
      {
        "_index": "movies",
        "_id": "e79oHIsByaLf0EuTjc3H",
        "_score": 0.18232156,
        "_source": {
          "title": "Harry Potter and the Prisoner of Azkaban"
        }
      }
    ]
  }
}

当我们搜索 analyzed_title 时,“pott” 前缀与属于我们两个文档的标记 “potter” 匹配。 因此,两份文件均被召回。

前缀乱序怎么办? 由于 title 中的单词被分词,我们期望 “potter harry” 与两个文档匹配。 但这是一个短语前缀查询,它尊重输入的顺序。 如果我们想要无序匹配,我们可以使用 match_bool_prefix。

GET /movies/_search
{
    "query": {
        "match_phrase_prefix": {
            "title.analyzed_title": {
                "query": "potter harry"
            }
        }
    }
}

上述查询将不会返回任何的结果。而如下的查询:

GET /movies/_search?filter_path=**.hits
{
  "query": {
    "match_bool_prefix": {
      "title.analyzed_title": {
        "query": "pott harr"
      }
    }
  }
}

将返回如下的结果:

{
  "hits": {
    "hits": [
      {
        "_index": "movies",
        "_id": "er9oHIsByaLf0EuTh81O",
        "_score": 1,
        "_source": {
          "title": "Harry Potter and the Chamber of Secrets"
        }
      },
      {
        "_index": "movies",
        "_id": "e79oHIsByaLf0EuTjc3H",
        "_score": 1,
        "_source": {
          "title": "Harry Potter and the Prisoner of Azkaban"
        }
      }
    ]
  }
}

这就是我要讨论的使用前缀查询自动完成的全部内容。 在选择此作为实现自动完成功能的方法时,我们需要考虑一些事项:

  • 这是最不推荐的方法,与其他自动完成(另外的两篇文章)实现相比,这种方法被认为是最慢的方法。 搜索速度很慢,因为我们在索引字段时没有做任何有助于自动完成查询的工作。 它被索引为一个简单的文本字段,将文档与查询文本进行匹配的大部分工作都是在搜索时完成的。 它将转到倒排索引并检查是否有任何标记以查询中提供的文本开头,这是一项昂贵的操作。
  • 在 Elasticsearch 的最新版本中,为术语级别前缀查询添加了 index_prefixes 选项,该选项允许通过将前缀存储在单独的字段中来加速前缀查询。
  • 如果你已经有一个工作索引并且不需要更新映射,那么前缀查询将是适合你的方法,因为自动完成不是系统中频繁使用的功能之一。 但如果是这样,那么你可能会遇到性能问题。 最好使用本系列下一部分中讨论的方法之一并重新索引数据。

如果你想了解这种方法的详细实现,请阅读 “Elasticsearch:创建一个 autocomplete 输入系统 - 前端 + 后端”。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1087031.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

低压配电系统中浪涌保护器的作用,安装位置和接线方法

低压配电系统是指在变压器低压侧或用户侧的电气装置&#xff0c;主要用于向用户提供安全、可靠和经济的电能。低压配电系统中常见的电气设备有低压配电柜、分支箱、开关箱、插座、照明等。这些设备都需要防止因外部或内部原因产生的过电压对其造成损坏或影响其正常工作。过电压…

帝国CMS《养生健康》模板/养生网站源码模板/健康模板+养生资讯+优化版

帝国CMS《健康养生》模板&#xff0c;简介大气访问快,养生源码模板,健康模板,百度自动推送,站内关键字改成直接调用tag标签&#xff0c;这样就方便对站内优化已比较好&#xff0c;经测试还容易产生词库。 采用帝国CMS7.5内核&#xff0c;开源不限域名&#xff0c;包含WAP手机端…

键盘录入涉及到的方法

键盘录入涉及到的方法 1&#xff09;next&#xff08;&#xff09;、nextLine&#xff08;&#xff09;&#xff1a; 可以接受任意数据&#xff0c;但是都会返回一个字符串。 2&#xff09;nextInt&#xff08;&#xff09;&#xff1a; 只能接受整数。 3&#xff09;next…

harbor的安装及使用

文章目录 安装harbor仓库具体安装过程测试上传 资源编排就是合理快速的分配计算资源和硬件资源&#xff0c;进行计算。 docker: swarm google: kubernetes (k8s,k3s) opensource: docker-compose 安装harbor仓库 0&#xff09; 创建/root/harbor目录&#xff0c;cd到此目录 …

同城二手市场生活源码系统+前后端完整搭建教程

大家好啊&#xff0c;今天罗峰给大家分享一个同城二手市场生活源码系统&#xff0c;二手市场在我们的日常生活中也比较常见&#xff0c;传统的二手市场操作起来不是很方便&#xff0c;这款小程序就轻松近实现在家足不出户就可以进行交易。以下是部分代码图&#xff1a; 系统特色…

多媒体应用设计师 第2章 多媒体信息处理及编辑技术

1.多媒体信息的种类与特点 视觉类&#xff1a;文字、图像、图形、视频、动画、其他&#xff08;视频、符号表示的数值、图形表示的某种数据曲线、数据库的关系数据&#xff09; 听觉类&#xff1a;波形声音、语音、音乐 多媒体信息特点&#xff1a; 多媒体是有格式的。 越接近…

CSS margin(外边距)

CSS margin(外边距)属性定义元素周围的空间。 margin margin 清除周围的&#xff08;外边框&#xff09;元素区域。margin 没有背景颜色&#xff0c;是完全透明的。 margin 可以单独改变元素的上&#xff0c;下&#xff0c;左&#xff0c;右边距&#xff0c;也可以一次改变所…

一键批量转换,轻松将TS视频转为MP4视频,实现更广泛的播放和分享!

在享受精彩视频内容的同时&#xff0c;有时我们可能会面临一个问题&#xff1a;某些视频格式可能不太适合我们的播放设备或分享平台。特别是TS格式的视频&#xff0c;在一些情况下可能无法直接播放或上传。但是不用担心&#xff0c;因为我们为您提供了一款强大的视频剪辑工具&a…

【AI】Datasets

文章目录 DatasetClassificationObject detectionSegmentationHumanFace图像质量 标注工具 Dataset Classification CIFAR-10CIFAR-100COCOImageNetMNISTSVHN Object detection COCOPASCAL VOCCaltech101 Segmentation COCOPASCAL VOCCityscapes datasetLVIS Human Cal…

kafka生产者发送消息报错 Bootstrap broker localhost:9092 (id: -1 rack: null) disconnected

报这个错误是因为kafka里的配置要修改下 在config目录下 server.properties配置文件 这下发送消息就不会一直等待&#xff0c;就可以发送成功了

日历视图,轻松解决时间管理难题_三叠云

日历组件 路径 仪表盘设计 >> 组件 功能简介 仪表盘新增「日历」组件。日历组件是以日历图的形式去呈现数据的一种方式&#xff0c;支持【列表模式】和【面板模式】。 【列表模式】&#xff1a; 通过日历方式筛选数据&#xff0c;数据将会以列表的方式呈现。 【面…

IDEA中点击New没有Java Class

解决办法&#xff1a;右键src&#xff0c;也可以是其他文件名&#xff0c;点击Mark Directory as 点击Sources Root即可

深度综述 | 肠道菌群通过改变宿主表观遗传影响宿主健康:中枢神经系统(CNS)疾病

大家好&#xff0c;这里是专注表观组学十余年&#xff0c;领跑多组学科研服务的易基因。 抑郁症、焦虑症和阿尔茨海默病&#xff08;Alzheimers disease&#xff0c;AD&#xff09;等中枢神经系统&#xff08;Central nervous system&#xff0c;CNS&#xff09;疾病会严重影响…

Python爬虫爬取某会计师协会网站的指定文章(文末送书)

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

苹果ios用户下载ipa文件内测签名的后的app应用下载安装到手机图标消失了-解决方案

下载好的应用竟然找不到了&#xff1f;这么神奇&#xff1f;我尝试了解了一下复原了同学给我的内容果然出现了我尝试科技了一下&#xff0c;总结了以下的可能性&#xff01;同学如果这个回答解决了你的困扰&#xff0c;同学给个赞&#xff0c;如果你有更好的排查方案评论区分享…

解锁知识管理3.0,生成式人工智能洞察新时代

原创 | 文 BFT机器人 鉴于我们不断使用最新、最好的解决方案&#xff0c;软件、技术和计算创新的巨大飞跃可能具有挑战性。人们很容易忘记技术过去的困境。但对于依赖及时信息和数据的行业&#xff08;例如企业知识管理&#xff09;来说&#xff0c;最新的管理技术能带来了巨大…

机器人革命:脑洞大开的前沿机器人技术!

原创 | 文 BFT机器人 01 由生物启发的多模式移动形态机器人 在一个不断运动的世界中&#xff0c;一种新开发的名为M4&#xff08;多模式移动形态机器人&#xff09;的机器人展示了在包括滚动、飞行和行走在内的八种不同运动模式之间切换的能力。这款机器人由加州理工学院自主…

Spring Boot 中的 TransactionTemplate 是什么,如何使用

Spring Boot中的TransactionTemplate&#xff1a;简化事务管理 事务管理是任何应用程序中至关重要的部分&#xff0c;特别是在处理数据库操作时。Spring Boot提供了多种方式来管理事务&#xff0c;其中之一是使用TransactionTemplate。本文将深入探讨TransactionTemplate是什么…

MFC为“对话框中的控件添加变量”,QT中使用“ui.对象名称”来调用控件

MFC中使用 向导 可以为“对话框中的控件添加变量”&#xff1b; 但是在QT中&#xff0c;一般都是使用“ui.对象名称”来调用控件&#xff01; 1、MFC中为“对话框中的控件添加变量”&#xff1b; 1.1 因为编辑框中的数据可能会经常变化&#xff0c;所以需要它们每个控件关联个…

Java多线程——线程状态以及线程礼让,线程休眠的区别(基于狂神说的学习笔记)

线程状态 线程的生命周期&#xff1a; 线程方法&#xff1a; 方法说明setPriority(int newPriority)更改线程的优先级static void sleep (long millis)在指定的毫秒数内让当前正在执行的线程体休眠void join ()等待该线程终止static void yield()暂停当前正在执行的线程对象&…