使用 Elasticsearch 进行语义搜索

Elasticsearch 是一款功能强大的开源搜索引擎,可用于全文搜索、分析和数据可视化。传统上,Elasticsearch 以其执行基于关键字/词汇的搜索的能力而闻名,其中文档基于精确或部分关键字匹配进行匹配。然而,Elasticsearch 已经发展到支持语义搜索 —— 一种专注于理解单词和短语背后的含义,而不仅仅是匹配关键字的方法。

Elasticsearch 中的语义搜索可实现更直观和上下文感知的搜索体验,即使查询中没有精确的关键字,也可以找到相关信息。本文将探讨如何在 Elasticsearch 中实现语义搜索、其优势和实际用例。

语义搜索

语义搜索是一种超越传统基于关键字的搜索的技术,它考虑了搜索查询的上下文、意图和含义。与专注于文字匹配的关键字搜索不同,语义搜索了解单词和概念之间的关系,从而实现更准确、更相关的搜索结果。

例如,在基于关键字的搜索中,查询 “laptop battery life” 可能会返回包含这些确切单词的文档。但是,语义搜索可能会返回讨论相关概念的文档,例如 “long-lasting laptops”、“energy-efficient devices”,甚至 “portable computers with extended battery life.”。

Elasticsearch 如何支持语义搜索

Elasticsearch 通过多种技术组合支持语义搜索,包括:

  • 向量表示:使用预训练模型(如 BERT(来自 Transformers 的双向编码器表示))将文本转换为可捕获语义含义的密集向量嵌入。
  • 相似度评分:测量查询向量和文档向量之间的相似度,以根据语义相关性对搜索结果进行排名。
  • 自定义分析器:创建自定义标记器、过滤器和分析器,以增强语义理解的方式预处理文本数据。
  • 与机器学习模型集成:利用与 Elasticsearch 集成的机器学习模型执行实体识别、情感分析等任务

架构 —— 使用 Elasticsearch 进行语义搜索

Elasticsearch 中两个非常重要的概念是文档和索引。

文档

文档是字段及其相关值的集合。每个文档都是一个 JSON 对象,其中包含结构化格式的数据。例如,代表一本书的文档可能包含标题、作者和出版日期等字段。

索引

索引是文档的集合,以高度优化的格式存储,旨在执行高效搜索。索引类似于关系数据库中的表,但它们更灵活,可以存储复杂的数据结构。

要使用 Elasticsearch,你需要将数据组织成文档,然后将所有文档添加到索引中。这使 Elasticsearch 能够根据搜索查询高效地搜索和检索相关文档。

在 Elasticsearch 中实现语义搜索

1. 设置 Elasticsearch

首先,确保你已启动并运行 Elasticsearch。你可以通过启动 Elasticsearch 的 Docker 容器来远程连接到 elasticsearch:

docker run -it \--rm \--name elasticsearch \-p 9200:9200 \-p 9300:9300 \-e "discovery.type=single-node" \-e "xpack.security.enabled=false" \docker.elastic.co/elasticsearch/elasticsearch:8.4.3

2. 数据加载和预处理

在此步骤中,我们将加载 documents.json 文件并对其进行预处理,以使层次结构扁平化,使其适合Elasticsearch。documents.json文件包含课程列表,每个课程都有一个文档列表。我们将提取每个文档并向其中添加一个课程字段,指示它属于哪个课程。

import jsonwith open('documents.json', 'rt') as f_in:docs_raw = json.load(f_in)

Elasticsearch 要求所有内容都处于同一层次结构中,在本例中,我们有两个层次,course 和 documents:

documents = []for course_dict in docs_raw:for doc in course_dict['documents']:doc['course'] = course_dict['course']documents.append(doc)documents[1]
#Output
{'text': 'GitHub - DataTalksClub data-engineering-zoomcamp#prerequisites','section': 'General course-related questions','question': 'Course - What are the prerequisites for this course?','course': 'data-engineering-zoomcamp'}

3. 使用预训练模型创建嵌入

要执行语义搜索,我们需要将文档转换为密集向量(嵌入),以捕获文本的语义含义。我们将使用来自 Sentence Transformers 库的预训练模型来生成这些嵌入。然后将这些嵌入编入 Elasticsearch 索引。这些嵌入使我们能够执行语义搜索,其目标是找到与给定查询上下文相似的文本。

文本和问题字段是包含主要信息的实际数据字段,而其他字段(如 section 和 course)则更具分类性,信息量较少,无法创建有意义的嵌入。

  • 安装 sentence_transformers 库。
  • 加载预训练模型并使用它来为我们的文档生成嵌入。
from sentence_transformers import SentenceTransformer
model = SentenceTransformer("all-mpnet-base-v2")#created the dense vector using the pre-trained model
operations = []
for doc in documents:# Transforming the title into an embedding using the modeldoc["text_vector"] = model.encode(doc["text"]).tolist()operations.append(doc)

4. 连接到 Elasticsearch

在此步骤中,我们将建立与 Elasticsearch 实例的连接。确保 Elasticsearch 正在运行。

from elasticsearch import Elasticsearch# Connect to the Elasticsearch instance
es_client = Elasticsearch('http://localhost:9200')
# Check the connection
print(es_client.info())

5. 创建映射和索引

我们将定义映射并在 Elasticsearch 中创建索引,生成的嵌入也将存储在其中。

映射是指定如何在 Elasticsearch 中构建和索引文档及其字段的过程。每个文档由各种字段组成,每个字段都分配有特定的数据类型。

与数据库模式类似,映射概述了文档的结构,详细说明了字段、它们的数据类型(例如字符串、整数或日期)以及如何索引和存储这些字段。

通过定义文档和索引,我们确保索引就像书中的目录一样,有助于高效搜索。

index_settings = {"settings": {"number_of_shards": 1,"number_of_replicas": 0},"mappings": {"properties": {"text": {"type": "text"},"section": {"type": "text"},"question": {"type": "text"},"course": {"type": "keyword"},"text_vector": {"type": "dense_vector", "dims": 768, "index": True, "similarity": "cosine"},}}
}index_name = "course-questions"
# Delete the index if it exists
es_client.indices.delete(index=index_name, ignore_unavailable=True)
# Create the index
es_client.indices.create(index=index_name, body=index_settings)

6. 将文档添加到索引

然后,我们将预处理后的文档及其嵌入添加到 Elasticsearch 索引中。这使得 Elasticsearch 能够有效地存储和管理文档,从而实现快速准确的搜索查询。

for doc in operations:try:es_client.index(index=index_name, document=doc)except Exception as e:print(e)

7. 查询搜索引擎

当用户输入搜索查询时,它会被转换为嵌入并在 Elasticsearch 索引中进行搜索。结果会根据其与查询的相关性进行评分。

search_term = "windows or mac?"
vector_search_term = model.encode(search_term)query = {"field": "text_vector","query_vector": vector_search_term,"k": 5,"num_candidates": 10000, 
}
res = es_client.search(index=index_name, knn=query, source=["text", "section", "question", "course"])
res["hits"]["hits"]

执行关键字搜索和高级搜索(过滤结果)

只要你直接使用用户输入并将该信息传递到你的搜索功能中,这就变成了关键字搜索。

response = es_client.search(index=index_name,query={"bool": {"must": {"multi_match": {"query": "windows or python?", "fields": ["text", "question","course","title"],"type": "best_fields"}},"filter": {"term": {"course": "data-engineering-zoomcamp"}}}}
)

执行语义搜索和高级搜索

为了让 Elasticsearch 执行语义搜索,我们应该传递从最终用户那里收到的信息并将其转换为向量嵌入,并且该向量嵌入是传递到搜索函数中的向量嵌入。

knn_query= {"field": "text_vector","query_vector":vector_search_term,"k": 5,"num_candidates" : 10000
}
response=es_client.search(index=index_name,query={"match": {"course": "data-engineering-zoomcamp"},},knn=knn_query,size=5,explain=True)

以下是主要步骤的简要介绍:

将从最终用户收到的搜索词转换为向量嵌入。

  • 将此向量嵌入传递到高级语义搜索函数中。
  • 将结果限制在特定部分,在本例中为 “General course-related questions”。同样,它可以限制为特定课程,例如 “Data Engineering Zoom Camp.”。基本语义搜索和高级语义搜索之间的一个显着区别在于结果的评分。基本语义搜索分数范围在 0 到 1 之间,其中 0 表示匹配度低,1 表示匹配度高。

使用 Explain 关键字解释分数为了进一步了解分数计算,Elasticsearch 提供了 explain=true 关键字。此工具描述了如何计算分数,提供了有价值的见解。有了这些信息,人们可以开发出更符合特定用户或业务需求的自定义评分函数。

更多阅读,请参阅:Elasticsearch:使用 Open AI 和 Langchain 的 RAG - Retrieval Augmented Generation (二)

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

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

相关文章

Kubeadm搭建k8s

一、架构 节点名称规格IP地址安装组件master012C/4G,cpu核心数要求大于2192.168.88.76docker、kubeadm、kubelet、kubectl、flannelnode012C/2G192.168.88.20docker、kubeadm、kubelet、kubectl、flannelnode022C/2G192.168.88.21docker、kubeadm、kubelet、kubect…

WordPress伪静态设置

为什么要设置WordPress伪静态,搜索引擎优化(SEO)中,静态URL通常被认为更易于搜索引擎爬虫抓取和索引,有助于提高网站的搜索引擎排名。 WordPress伪静态设置方法主要依赖于服务器环境,以下是针对不同服务器…

【简道云 -注册/登录安全分析报告】

前言 由于网站注册入口容易被黑客攻击,存在如下安全问题: 暴力破解密码,造成用户信息泄露短信盗刷的安全问题,影响业务及导致用户投诉带来经济损失,尤其是后付费客户,风险巨大,造成亏损无底洞…

太速科技-712-6U VPX飞腾处理器刀片计算机

6U VPX飞腾处理器刀片计算机 一、产品概述 该产品是一款基于国产飞腾FT-2000四核处理器或D2000八核处理器的高性能6U VPX刀片式计算机。产品提供了可支持全网状交换的高速数据通道,其中P1、P2均支持1个PCIe x16 Gen3或2个PCIe x8 Gen3或4个PCIe x4 Gen3总…

安卓设备adb执行AT指令控制电话卡

文章目录 AT指令起源与发展:基本格式:常见应用领域及功能:不同设备中的应用: 安卓获取modem设备输入符入口安卓设备输入AT指令 AT指令 AT 指令是 Attention 的缩写,是一种用于控制调制解调器等通信设备的指令集。 起…

c++模板入门

c系列模板入门 文章目录 c系列模板入门一、模板概念引入二、函数模板2.1、函数模板的概念2.2、函数模板的定义格式2.3、函数模板的使用 三、类模板1.1、什么是类模板1.2、类模板的定义格式1.3、类模板于函数模板的区别 一、模板概念引入 在程序设计中我们经常需要对两个数据进…

谷粒商城のsentinelzipkin

文章目录 前言一、Sentinel1、什么是Sentinel2、项目配置3、使用案例3.1、流控3.2、降级3.3、黑白名单设置 二、Zipkin1、什么是Zipkin2、项目配置3、整合案例 前言 本篇介绍Spring Cloud Ali的sentinel组件,用于对微服务的熔断降级,以及链路追踪zipkin的…

Freertos学习日志(1)-基础知识

目录 1.什么是Freertos? 2.为什么要学习RTOS? 3.Freertos多任务处理的原理 1.什么是Freertos? RTOS,即(Real Time Operating System 实时操作系统),是一种体积小巧、确定性强的计算机操作系统…

2. Flink快速上手

文章目录 1. 环境准备1.1 系统环境1.2 安装配置Java 8和Scala 2.121.3 使用集成开发环境IntelliJ IDEA1.4 安装插件2. 创建项目2.1 创建工程2.1.1 创建Maven项目2.1.2 设置项目基本信息2.1.3 生成项目基本框架2.2 添加项目依赖2.2.1 添加Flink相关依赖2.2.2 添加slf4j-nop依赖2…

TIA 中用 GSD 方式组态 ET200SP 安全模块时如何用 S7-FCT 分配安全目标地址

1 概述 用 GSD 方式组态的 ET200SP 的分布式从站上,现在可以使用安全模块(早期 是无法支持),这种用法对 ET200SP 接口模块的版本和编程软件的版本都有要求。 ET200SP 故障安全模块可通过 GSD 文件用于以下接口模块: …

0,国产FPGA(紫光同创)-新建PDS工程

国产FPGA正在蓬勃发展,紫光同创FPGA是大家竞赛时经常遇到的一款国产FPGA,本专栏从IP核开始一直到后续图像处理等。 开发板:盘古50K标准板 1,新建PDS工程 点击File(1),然后是New Projects&#…

视频Qoe测量学习笔记(一)

目录 流媒体协议详解 RTSP:实时流式协议 RTCP:实时运输控制协议 RTP:实时运输协议 H.264 流媒体协议详解 RTSP:实时流式协议 由IETF MMusic小组开发,已成为互联网建议标准[RFC 2326]。RTSP本身并不传送数据&…

计算机视觉常用数据集Foggy Cityscapes的介绍、下载、转为YOLO格式进行训练

我在寻找Foggy Cityscapes数据集的时候花了一番功夫,因为官网下载需要用公司或学校邮箱邮箱注册账号,等待审核通过后才能进行下载数据集。并且一开始我也并不了解Foggy Cityscapes的格式和内容是什么样的,现在我弄明白后写下这篇文章&#xf…

单向函数、单向陷门函数、困难问题

1、单向函数 设函数 yf(x) , 对于给定的x,计算出y很容易;对于给定的y,计算出x很难。 2、单向陷门函数 设函数 yf(x) ,且f有陷门, 对于给定的x,计算出y很容易;对于给定的y&#…

js 获取当前时间与前一个月时间

// 获取当前时间的毫秒数 var currentTimeMillis new Date().getTime();// 获取前一个月的Date对象 var dateLastMonth new Date(); dateLastMonth.setMonth(dateLastMonth.getMonth() - 1);// 获取前一个月的毫秒数 var timeMillisLastMonth dateLastMonth.getTime();conso…

Linux_02 Linux常用软件——vi、vim

vi编辑器有三种主要模式,每种模式的功能和用途不同: 一、命令模式 (Command Mode): - 启动 vi 时默认进入此模式。 - 你可以在此模式下移动光标,输入各种命令(如删除、复制、粘贴等)。 yy:…

C++设计模式结构型模式———装饰模式

文章目录 一、引言二、装饰器模式三、总结 一、引言 装饰模式是一种结构型设计模式, 允许你通过将对象放入包含行为的特殊封装对象中来为原对象绑定新的行为。 该模式展现出了运行时的一种扩展能力,以及比继承更强大和灵活的设计视角和设计能力&#x…

「iOS」——知乎日报一二周总结

知乎日报仿写 前言效果Manager封装网络请求线程冲突问题下拉刷新添加网络请求的图片通过时间戳和日期格式化获取时间 总结 前言 前两周内容的仿写,主要完成了首页的仿写,进度稍慢。 效果 Manager封装网络请求 知乎日报的仿写需要频繁的申请网络请求&am…

Profinet、Ethernet/IP 工业以太网无线通信解决方案

在工业现场,我们常常会面临这样的困扰:两个PLC之间、PLC 跟远程IO之间或者PLC 跟伺服之间由于种种原因不方便布线,严重影响了通讯效率和生产进程。为了解决这一难题,三格电子设计了一款工业以太网无线网桥,这款无线网桥…

【数据结构】二叉树——前中后序遍历

一、如何遍历二叉树 以图上这个二叉树作为例子,我们若想要访问二叉树中每一个元素 我们一般是采用递归的方式 比如我们要访问完整个二叉树,我们进行递归先访问根的左子树,然后因为递归再次调用,我们会先一直访问二叉树左子树&…