Elasticsearch:Search tutorial - 使用 Python 进行搜索 (四)

在本节中,你将了解另一种机器学习搜索方法,该方法利用 Elastic Learned Sparse EncodeR 模型或 ELSER,这是一种由 Elastic 训练来执行语义搜索的自然语言处理模型。这是继之前的文章 “Elasticsearch:Search tutorial - 使用 Python 进行搜索 (三)” 的续篇。

ELSER 模型

在上一章中,您了解了如何使用由机器学习模型生成的嵌入填充的 dend_vector 字段来扩展 Elasticsearch 索引。 该模型安装在你的计算机本地,嵌入是从 Python 代码生成的,并在插入索引之前添加到文档中。

在本章中,你将了解另一种向量类型,sparse_vector,它旨在存储来自 Elastic Learned Sparse EncodeR 模型 (ELSER) 的推论。 该模型返回的嵌入是标签的集合(更恰当地称为特征),每个标签都具有指定的权重。

在本章中,你还将使用不同的方法来处理机器学习模型,其中 Elasticsearch 服务本身运行模型并通过管道将生成的嵌入添加到索引中。

稀疏向量字段

与上一章中使用的密集向量字段类型一样,稀疏向量类型可以存储机器学习模型返回的推论。 密集向量保存描述源文本的固定长度的数字数组,而稀疏向量则存储特征到权重的映射。

让我们向索引添加一个稀疏向量字段。 这是需要在索引映射中显式定义的类型。 下面你可以看到 create_index() 方法的更新版本,其中包含一个名为 elser_embedding 的此类型的新字段。

search.py

class Search:# ...def create_index(self):self.es.indices.delete(index='my_documents', ignore_unavailable=True)self.es.indices.create(index='my_documents', mappings={'properties': {'embedding': {'type': 'dense_vector',},'elser_embedding': {'type': 'sparse_vector',},}})# ...

部署 ELSER 模型

如上所述,在此示例中,Elasticsearch 将获得模型的所有权并在插入文档和搜索时自动执行它以生成嵌入。

Elasticsearch 客户端公开一组 API 端点来管理机器学习模型及其管道。 search.py 中的以下 deploy_elser() 方法遵循几个步骤来下载和安装 ELSER v2 模型,并创建一个使用它来填充上面定义的 elser_embedding 字段的管道。

search.py

class Search:# ...def deploy_elser(self):# download ELSER v2self.es.ml.put_trained_model(model_id='.elser_model_2',input={'field_names': ['text_field']})# wait until readywhile True:status = self.es.ml.get_trained_models(model_id='.elser_model_2',include='definition_status')if status['trained_model_configs'][0]['fully_defined']:# model is readybreaktime.sleep(1)# deploy the modelself.es.ml.start_trained_model_deployment(model_id='.elser_model_2')# define a pipelineself.es.ingest.put_pipeline(id='elser-ingest-pipeline',processors=[{'inference': {'model_id': '.elser_model_2','input_output': [{'input_field': 'summary','output_field': 'elser_embedding',}]}}])

为我们配置 ELSER 需要几个步骤。 首先,使用 Elasticsearch 的 ml.put_trained_model() 方法下载ELSER。 model_id 参数标识要下载的模型和版本(ELSER v2 适用于 Elasticsearch 8.11 及更高版本)。 input 字段是该模型所需的配置。

下载模型后,需要对其进行部署。 为此,使用 ml.start_trained_model_deployment() 方法,仅使用要部署的模型的标识符。 请注意,这是一个异步操作,因此该模型将在短时间内可供使用。

配置 ELSER 使用的最后一步是为其定义管道。 管道用于告诉 Elasticsearch 如何使用模型。 管道被赋予一个标识符和一个或多个要执行的处理任务。 上面创建的管道称为 elser-ingest-pipeline,具有单个推理任务,这意味着每次添加文档时,模型将在 input_field 上运行,并且输出将添加到 输出字段。 对于此示例,summary 字段用于生成嵌入,与上一章中的密集向量嵌入一样。 生成的嵌入将写入上一节中创建的 elser_embedding 稀疏向量字段。

为了方便调用此方法,请在 app.py 中的 Flask 应用程序中添加一个 deploy-elser 命令:

app.py

@app.cli.command()
def deploy_elser():"""Deploy the ELSER v2 model to Elasticsearch."""try:es.deploy_elser()except Exception as exc:print(f'Error: {exc}')else:print(f'ELSER model deployed.')

你现在可以使用以下命令在 Elasticsearch 服务上部署 ELSER:

(.venv) $ pwd
/Users/liuxg/python/search-tutorial
(.venv) $ flask deploy-elser
Connected to Elasticsearch!
{'cluster_name': 'elasticsearch','cluster_uuid': 'SXGzrN4dSXW1t0pkWXGfjg','name': 'liuxgm.local','tagline': 'You Know, for Search','version': {'build_date': '2023-11-04T10:04:57.184859352Z','build_flavor': 'default','build_hash': 'd9ec3fa628c7b0ba3d25692e277ba26814820b20','build_snapshot': False,'build_type': 'tar','lucene_version': '9.8.0','minimum_index_compatibility_version': '7.0.0','minimum_wire_compatibility_version': '7.17.0','number': '8.11.0'}}
ELSER model deployed.

上面的命令的允许需要一段时间。等命令完成后,我们可以转到 Kibana 界面:

最后一个配置任务涉及将索引与管道链接,以便在该索引上插入文档时自动执行模型。 这是通过设置选项在索引配置上完成的。 以下是对 create_index() 方法的另一项更新,用于创建此链接:

search.py

class Search:# ...def create_index(self):self.es.indices.delete(index='my_documents', ignore_unavailable=True)self.es.indices.create(index='my_documents',mappings={'properties': {'embedding': {'type': 'dense_vector',},'elser_embedding': {'type': 'sparse_vector',},}},settings={'index': {'default_pipeline': 'elser-ingest-pipeline'}})

通过此更改,你现在可以重新生成索引并完全支持 ELSER 推理:

flask reindex
(.venv) $ pwd
/Users/liuxg/python/search-tutorial
(.venv) $ flask reindex
Connected to Elasticsearch!
{'cluster_name': 'elasticsearch','cluster_uuid': 'SXGzrN4dSXW1t0pkWXGfjg','name': 'liuxgm.local','tagline': 'You Know, for Search','version': {'build_date': '2023-11-04T10:04:57.184859352Z','build_flavor': 'default','build_hash': 'd9ec3fa628c7b0ba3d25692e277ba26814820b20','build_snapshot': False,'build_type': 'tar','lucene_version': '9.8.0','minimum_index_compatibility_version': '7.0.0','minimum_wire_compatibility_version': '7.17.0','number': '8.11.0'}}
Index with 15 documents created in 59 milliseconds.

运行完上面的命令后,我们可以在 Kibana 里进行查看:

从上面的图中我们可以看出来,有一个叫做 elser_embedding 的字段生成。它里面所含的值就是通过 text expansion 所生成的。

语义查询

现在索引配备了 ELSER 嵌入,可以更改 app.py 中的 handle_search() 函数来搜索这些嵌入。 目前,你将了解如何仅通过 ELSER 进行搜索,稍后将合并以前的搜索方法以创建组合解决方案。

要在搜索时使用 ELSER 推理,请使用 text_expansion 查询类型。 下面你可以看到带有此查询的更新后的 handle_search() 函数:

app.py

@app.post('/')
def handle_search():query = request.form.get('query', '')filters, parsed_query = extract_filters(query)from_ = request.form.get('from_', type=int, default=0)results = es.search(query={'text_expansion': {'elser_embedding': {'model_id': '.elser_model_2','model_text': parsed_query,}},},size=5,from_=from_,)return render_template('index.html', results=results['hits']['hits'],query=query, from_=from_,total=results['hits']['total']['value'])

text_expansion 查询接收一个带有要搜索的字段名称的键。 在此键下,model_id 配置在搜索中使用哪个模型,model_text 定义要搜索的内容。 请注意,在这种情况下,无需为搜索文本生成嵌入,因为 Elasticsearch 管理模型并可以处理该问题。我们可以尝试如下的搜索:

在上面版本的handle_search()中,过滤器未被使用。 过滤器可以按照将其合并到全文搜索解决方案中的相同方式添加回来。 下面是更新的 handle_search() 函数,它将 text_expansion 查询移动到 bool.must 部分内,过滤器包含在 bool.filter 中。

app.py

@app.post('/')
def handle_search():query = request.form.get('query', '')filters, parsed_query = extract_filters(query)from_ = request.form.get('from_', type=int, default=0)results = es.search(query={'bool': {'must': [{'text_expansion': {'elser_embedding': {'model_id': '.elser_model_2','model_text': parsed_query,}},}],**filters,}},size=5,from_=from_,)return render_template('index.html', results=results['hits']['hits'],query=query, from_=from_,total=results['hits']['total']['value'])

花一些时间尝试不同的搜索。 你会注意到,与密集向量嵌入一样,当索引文档中没有出现确切的单词时,由 ELSER 模型驱动的搜索比全文搜索效果更好。

work from home category:sharepoint

混合搜索:结合全文和 ELSER 结果

与上一节中的向量搜索一样,在本节中,你将学习如何使用倒数排名融合(RRF)算法组合来自全文和语义查询的最佳搜索结果。

子搜索简介

实现混合全文和密集向量搜索的解决方案是发送一个搜索请求,其中包括 query、knn  参数来请求两个搜索以及将它们合并到单个结果列表中的 rrf 参数。

当尝试执行相同操作来组合全文和稀疏向量搜索请求时,出现的复杂情况是两者都使用 query 参数。 为了能够提供需要与 RRF 算法结合的两个查询,需要包含两个查询参数,而实现这一点的解决方案是使用子搜索 (sub searches)来完成。

子搜索是一项目前处于技术预览版的功能。 因此,Python Elasticsearch 客户端本身并不支持它。 要解决此限制,可以更改 Search 类的 search() 方法以将搜索请求作为原始请求发送。 下面你可以看到一个新的但类似的实现,它使用客户端的 Perform_request() 方法发送原始请求:

search.py

class Search:# ...def search(self, **query_args):# sub_searches is not currently supported in the client, so we send# search requests as raw requestsif 'from_' in query_args:query_args['from'] = query_args['from_']del query_args['from_']return self.es.perform_request('GET',f'/my_documents/_search',body=json.dumps(query_args),headers={'Content-Type': 'application/json','Accept': 'application/json'},)

此实现不需要对应用程序进行任何更改,因为它在功能上是等效的。 唯一的区别是 search() 方法在发送请求之前验证所有参数,而 Perform_request() 是一个较低级别的方法,不执行任何验证。 无论客户端如何发送请求,服务器始终都会验证请求。

在此版本中,sub_searches 参数可用于发送多个搜索查询,如下所示:

results = es.search(sub_searches=[{'query': { ... },  # full-text search},{'query': { ... },  # semantic search},],'rank': {'rrf': {},  # combine sub-search results},size=5,from_=from_,)

混合搜索实施

为了完成本节,让我们带回全文逻辑并将其与本章前面介绍的语义搜索查询相结合。

你可以在下面看到更新后的 handle_search() 端点:

app.py

@app.post('/')
def handle_search():query = request.form.get('query', '')filters, parsed_query = extract_filters(query)from_ = request.form.get('from_', type=int, default=0)if parsed_query:search_query = {'sub_searches': [{'query': {'bool': {'must': {'multi_match': {'query': parsed_query,'fields': ['name', 'summary', 'content'],}},**filters}}},{'query': {'bool': {'must': [{'text_expansion': {'elser_embedding': {'model_id': '.elser_model_2','model_text': parsed_query,}},}],**filters,}},},],'rank': {'rrf': {}},}else:search_query = {'query': {'bool': {'must': {'match_all': {}},**filters}}}results = es.search(**search_query,size=5,from_=from_,)return render_template('index.html', results=results['hits']['hits'],query=query, from_=from_,total=results['hits']['total']['value'])

你还记得,extract_filters() 函数查找用户在搜索提示中输入的类别过滤器,并将剩余部分作为 parsed_query 返回。 如果 parsed_query 为空,则意味着用户仅输入类别过滤器,在这种情况下,查询应该是简单的 match_all,并以所选类别作为过滤器。 这是在大条件的 else 部分中实现的。

当存在搜索查询时,如上一节所示,使用 sub_searches 选项来包含 multi_match 和 text_expansion 查询,而排名选项则要求将两个子搜索的结果合并到单个排名结果列表中。 为了完成查询,提供了 size 和 from_ 参数以维持对分页的支持。

我们可以尝试上面同样的搜索:

从上面的输出结果中,我们可以看出来它的搜索结果和之前的很相似,但是它融合了关键字搜索及语义搜索。在某些应用场合,它会更为精确。

我们可以在地址下载最后完整的代码:

git clone https://github.com/liu-xiao-guo/search-tutorial-3

结论

恭喜你已完成搜索教程!

我们希望本教程为你提供了一个基础,你可以在此基础上开始使用 Elasticsearch 进行实验并创建你的搜索解决方案!

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

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

相关文章

git ssh key 配置

一、Profile Settings-->SSH Keys 我们点击这里会有详情的文档介绍生成sshkey。 ssh-keygen -t rsa -b 2048 -C "邮箱" --回车... 将生成的id_rsa.pub粘贴到如下保存 git config --global user.name "用户名" git config --global user.email "邮…

js(JavaScript)数据结构之数组(Array)

什么是数据结构? 下面是维基百科的解释: 数据结构是计算机存储、组织数据的方式。数据结构意味着接口或封装:一个数据结构可被视为两个函数之间的接口,或者是由数据类型联合组成的存储内容的访问方法封装。 我们每天的编码中都会…

HackTheBox - Medium - Linux - Faculty

Faculty Faculty 是一台中型 Linux 机器,具有 PHP Web 应用程序,该应用程序使用的库容易受到本地文件包含的影响。利用该库中的 LFi 会泄露一个密码,该密码可用于通过 SSH 以名为“gbyolo”的低级用户身份登录。用户“gbyolo”有权作为“dev…

Linux 内核如何根据设备树文件来匹配内核

一. 简介 上一篇文章学习了 Linux内核如何确定是否支持此设备,如果支持,设备就会启动 Linux 内核。 文章地址如下: 设备树根节点下的compatile属性的作用-CSDN博客 本文继上面文章的学习。这里简单看一下, Linux 内核是如何根…

iOS App自动化测试:从环境搭建到实际应用(Python+pytest+appium+allure框架)

iOS App自动化测试:Pythonpytestappiumallure 一、环境准备: 1.1 Appium环境搭建 Windows端:Windows端appium环境搭建Mac端:Mac端appium环境搭建 总结:appium-doctor 是用来检测环境配的是否完整,安装完…

java进阶||jdk进阶之循环

从18年学java到现在除了各种各样的数据类型和集合烧不了要遍历这些变量, for循环这时就少不了啦(当然还有8后引入的神器泛型) 先来看一段精髓业务代码, 使用了多个新特性当然也少不了循环和分支判断 代码较长解析在后面 private CommonPage<List<Object>> handle…

【MyBatis】动态SQL

文章目录 前言增加操作\<trim>标签查询操作\<where>标签修改操作\<set>标签删除操作\<foreach>标签\<include>标签 前言 动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架&#xff0c;你应该能理解根据不同条件拼接 SQ…

超声波清洗机可以洗些什么东西?质量比较好的超声波清洗机推荐

超声波清洗机只能清洗眼镜吗&#xff1f;不是的&#xff01;超声波清洗机能够清洗的物品远比我们想象的还多&#xff0c;最常见的还是清洗眼镜&#xff0c;毕竟超声波清洗机最常见就是在眼镜店了&#xff0c;很多朋友都喜欢定期都眼镜店里来清洗一下眼镜&#xff0c;这个习惯其…

vivado Revision Control

2020.2 只需要git 管理 prj.xpr 和 prj.srcs/ https://china.xilinx.com/video/hardware/ip-revision-control.html Using Vivado Design Suite with Revision Control https://www.xilinx.com/video/hardware/vivado-design-suite-revision-control.html http://www.xi…

腾讯实验平台基于 StarRocks 构建湖仓底座

作者&#xff1a; 腾讯大数据平台部科学实验中心Tech Lead、专家工程师 马金勇博士 腾讯大数据平台部科学实验中心数据负责人、专家工程师 胡明杰 StarRocks Contributor、腾讯高级工程师 刘志行 在 2022 年&#xff0c;腾讯 A/B Test 团队启动了海外商业化版本 ABetterChoice …

企业网络两层和三层架构部署有何差异

知识改变命运&#xff0c;技术就是要分享&#xff0c;有问题随时联系&#xff0c;免费答疑&#xff0c;欢迎联系&#xff01; 厦门微思网络​​​​​​ https://www.xmws.cn华为认证\华为HCIA-Datacom\华为HCIP-Datacom\华为HCIE-Datacom Linux\RHCE\RHCE 9.0\RHCA\ Oracle OC…

html的全选反选

一、实验题目 html实现选择框的全选和反选 二、实验代码 <!DOCTYPE html> <html><head><meta charset"utf-8"><title>全选和反选</title></head><body><ul>兴趣爱好</ul><input id"all"…

【AI】 AIOTSummary

智能物联网(AIoT)是2018年兴起的概念,指系统通过各种信息传感器实时采集 各类信息(一般是在监控、互动、连接情境下的),在终端设备、边缘域或云中心 通过机器学习对数据进行智能化分析,包括定位、比对、预测、调度等。智能物联网(AIoT)是2018年兴起的概念,指系统通过…

微软等开源评估ChatGPT、Phi、Llma等,统一测试平台

微软亚洲研究院、中国科学院自动化研究所、中国科学技术大学和卡内基梅隆大学联合开源了&#xff0c;用于评估、分析大语言模型的统一测试平台——PromptBench。 Prompt Bench支持目前主流的开源、闭源大语言模型&#xff0c;例如&#xff0c;ChatGPT、GPT-4、Phi、Llma1/2、G…

基于虚拟机安装centos且远程连接

基于虚拟机安装centos且远程连接 1、安装虚拟机 目前市面上的虚拟机种类有很多&#xff0c;我们可以选择自己熟悉的虚拟机进行安装&#xff0c;我在这里用的虚拟机是VMware。具体的安装过程很简单&#xff0c;一直点击下一步就可以了。因为VMware虚拟机需要激活&#xff0c;所…

AI语音识别模块--whisper模块

1.下载 ffmpeg&#xff0c;挑一个自己电脑系统的版本&#xff0c;下载&#xff0c;如我win64&#xff1a; 地址&#xff1a; Releases BtbN/FFmpeg-Builds GitHub 下载压缩包zip&#xff0c;到本地 解压安装&#xff0c;其实无需安装&#xff0c;只需把对应的目录下的bin&…

【Matlab】在Matlab中安装优化工具yalmip的方法

最近博主想做一些关于多目标优化的问题&#xff0c;因为之前对Matlab有一定经验&#xff0c;所以直接在网上查找了如何在Matlab上实现多目标优化的文献&#xff0c;看到有人提到了yamip&#xff0c;于是博主就试着在Matlab中安装yamip&#xff0c;将其中遇到的问题和一些经验和…

缓存学习实战篇

缓存练习题&#xff08;用户查询操作&#xff09; public List<ShopType> queryAllType() throws JsonProcessingException {//从缓存中查数据String shopTypeJson stringRedisTemplate.opsForValue().get("cache:shopType");//如果缓存命中&#xff0c;if (S…

申请ZeroSSL泛域名域名证书 并部署阿里云测试

安装acme.sh 安装过程中可能会失败 多试几次就会成功 wget -O - https://raw.githubusercontent.com/acmesh-official/acme.sh/master/acme.sh | sh -s -- --install-online -m 你的邮箱gmail.com安装完成后重新加载 Bash&#xff1a; source ~/.bashrc然后也可以开启自动更…

客户端请求服务器的步骤

当我们在浏览器地址栏输入’http://www.xxx.com/api/xxx"时&#xff0c;客户端是如何找到服务器并发送请求的&#xff1f; 1.先找到服务器 a.检测浏览器缓存有没有缓存该域名对应的IP地址&#xff0c;有则通过IP地址取找服务器。 b.检测本地的hosts文件&#xff0c;是否有…