使用 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 (二)
相关文章:
使用 Elasticsearch 进行语义搜索
Elasticsearch 是一款功能强大的开源搜索引擎,可用于全文搜索、分析和数据可视化。传统上,Elasticsearch 以其执行基于关键字/词汇的搜索的能力而闻名,其中文档基于精确或部分关键字匹配进行匹配。然而,Elasticsearch 已经发展到支…...
软考:中间件
中间件 中间件是一类位于操作系统软件与用户应用软件之间的计算机软件,它包括一组服务,以便于运行在一台或多台机器上的多个软件通过网络进行交互。 中间件的主要功能包括通信支持和应用支持。 通信支持为应用软件提供平台化的运行环境,屏蔽…...
银行家算法(Banker’s Algorithm)
银行家算法(Banker’s Algorithm)是计算机操作系统中一种避免死锁发生的著名算法。该算法由艾兹格迪杰斯特拉(Edsger Dijkstra)在1965年为T.H.E系统设计,其核心理念基于银行借贷系统的分配策略,以确保系统的…...
用魔数严谨的判别文件类型:杜绝上传风险
在文件处理和管理中,确定文件的类型是一个常见的需求。虽然文件扩展名可以提供一些信息,但并不总是可靠的。魔数(Magic Numbers)是一种更为准确的方法,通过检查文件开头的特定字节序列来识别文件类型。本文将介绍如何在…...
【MacOS实操】如何基于SSH连接远程linux服务器
MacOS上远程连接linux服务器,可以使用ssh命令pem秘钥文件连接。 一、准备pem秘钥文件 如果已经有pem文件,则跳过这一步。如果手上有ppk文件,那么需要先转换为pem文件。 macOS 的默认 SSH 客户端不支持 PPK 格式,你需要将 PPK 文…...
EXPLAIN 针对性优化 SQL 查询
在数据库管理和应用中,高效的 SQL 查询是确保系统性能的关键。随着数据量的不断增长和业务需求的日益复杂,优化 SQL 查询变得尤为重要。而 EXPLAIN 命令是一种强大的工具,可以帮助我们深入了解 SQL 查询的执行计划,从而进行有针对…...
MR30分布式IO:石化行业的智能化革新
在浩瀚的工业领域中,石化行业如同一座巨大的化工厂,将自然界的原始资源转化为人们日常生活中不可或缺的各种产品。然而,随着生产规模的扩大和工艺复杂度的提升,石化行业面临着前所未有的挑战:如何在保证生产效率的同时…...
linux图形化X窗口
【linux图形化协议框架】 X、X11系统:X协议,X服务器,窗口管理器,X客户端(客户端库Xcb,Xlib库等),输入、绘制 Wayland系统:Wayland 协议,合成器、客户端&#…...
练习LabVIEW第三十五题
学习目标: 刚学了LabVIEW,在网上找了些题,练习一下LabVIEW,有不对不好不足的地方欢迎指正! 第三十五题: 使用labview模拟一个3-8译码器 开始编写: 用LabVIEW做3-8译码器首先要知道它是个啥…...
Decision Tree Regressor (决策树) --- 论文实战
一、前言 在《机器学习论文复现实战---linear regression》中通过Pearson 相关性分析,去除了2个高相关性特征 "PN" 和 "AN" ,数据维度变为890*25。(数据集地址) 这里我们不做前期处理,直接就将数据放入 DecisionTreeRegressor 模型中进行训练了。 二…...
三层交换技术,eNSP实验讲解
三层交换技术,eNSP实验讲解 一、简要介绍1、概念2、工作原理3、优点4、应用场景5、与路由器的区别 二、eNSP仿真实验1、步骤一:创建连接,明确参数。2、步骤二:设置PC1和PC2参数3、步骤三:配置交换机,通过命…...
单链表OJ题(3):合并两个有序链表、链表分割、链表的回文结构
目录 一、合并两个有序链表 二、链表分割 三、链表的回文结构 u解题的总体思路: 合并两个有序链表:首先创建新链表的头节点(哨兵位:本质上是占位子),为了减少一些判断情况,简化操作。然后我们…...
研究了100个小绿书十万加之后,我们发现2024小绿书独家秘籍就是:在于“先抄后超,持续出摊,量大管饱”!
小绿书作为今年最大的红利,很多人已经吃到了螃蟹。看——: 今天我们总结了100个10万爆款,我们发现要在这个平台上脱颖而出,找到属于自己的方法尤为重要。在这里分享一个主题——小绿书的秘诀就是“先抄后超,持续出摊”…...
Java 中 HashMap集合使用
目录 一. HashMap概述 二. HashMap特点 三. HashMap构造方法 四. HashMap的常用方法 五. 使用注意事项 六. 代码示例 一. HashMap概述 HashMap 是 Java 中的一个非常重要的类,它实现了 Map 接口,用于存储键值对(key-value pairs&#…...
#渗透测试#SRC漏洞挖掘# 信息收集-Shodan进阶之Mongodb未授权访问
免责声明 本教程仅为合法的教学目的而准备,严禁用于任何形式的违法犯罪活动及其他商业行为,在使用本教程前,您应确保该行为符合当地的法律法规,继续阅读即表示您需自行承担所有操作的后果,如有异议,请立即停…...
平台化运营公司如何在创业市场招商
在当今商业环境中,平台化运营的公司正成为推动经济发展的重要力量。对于这类公司而言,在创业市场招商意义重大。 平台化运营公司具有独特特点:通过搭建开放共享平台连接供需双方,实现资源优化配置与价值创造。比如电子商务平台、社…...
飞书API-获取tenant_access_token
1.在飞书工作台创建应用,跳到开发者后台,选创建企业自建应用 2.设置并发布应用 必须要发布应用才可以开始使用了!!! 3.调用获取token的API 参考链接: 开发文档 - 飞书开放平台https://open.feishu.cn/do…...
(新)docker desktop镜像迁移
背景 docker desktop默认安装在系统c盘,久而久之随着镜像拉取的越多,系统盘占用则越来越大。现有的网络资源关于docker desktop迁移都是旧版本的,即4.30版本之前。在4.30版本及以后,在运行wsl -l -v时只有docker-desktop只有这一项…...
单向函数、单向陷门函数、困难问题
1、单向函数 设函数 yf(x) , 对于给定的x,计算出y很容易;对于给定的y,计算出x很难。 2、单向陷门函数 设函数 yf(x) ,且f有陷门, 对于给定的x,计算出y很容易;对于给定的y&#…...
MYSQL 小猫钓鱼 - 猫王争霸之〈主从设计〉
在美丽的森林中,小猫们的钓鱼大赛依旧热闹非凡,而 “猫王争霸” 的竞争也越来越激烈。随着时间的推移,越来越多的动物们开始关注这场有趣的比赛,对鱼表数据的查询请求也急剧增加。 一、请求压力剧增 花猫看着鱼表发愁道…...
AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版分享
平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...
UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...
跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...
土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等
🔍 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术,可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势,还能有效评价重大生态工程…...
[Java恶补day16] 238.除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O(n) 时间复杂度…...
CMake控制VS2022项目文件分组
我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...
ip子接口配置及删除
配置永久生效的子接口,2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...
【Go语言基础【13】】函数、闭包、方法
文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...
