Elasticsearch:Serarch tutorial - 使用 Python 进行搜索 (二)
这个是继上一篇文章 “Elasticsearch:Serarch tutorial - 使用 Python 进行搜索 (一)” 的续篇。在今天的文章中,我们接着来完成如何进行分页及过滤。
分页 - pagination
应用程序处理大量结果通常是不切实际的。 因此,API 和 Web 服务使用分页控件来允许应用程序请求小块或页面的结果。
你可能已经注意到,Elasticsearch 默认情况下不会返回超过 10 个结果。 可以在搜索请求中给出可选的大小参数来更改此最大值。 以下示例要求最多返回 5 个搜索结果:
results = es.search(query={'multi_match': {'query': query,'fields': ['name', 'summary', 'content'],}}, size=5
)
要访问结果的其他页面,请使用 from_ 参数,该参数指示从完整结果列表中的位置开始(因为 from 是 Python 中的保留关键字,所以使用 from_ )。
下一个示例检索第二页 5 个结果:
results = es.search(query={'multi_match': {'query': query,'fields': ['name', 'summary', 'content'],}}, size=5, from_=5
)
让我们将 size 和 from_ 合并到 app.py 中的 handle_search() 端点中:
@app.post('/')
def handle_search():query = request.form.get('query', '')from_ = request.form.get('from_', type=int, default=0)results = es.search(query={'multi_match': {'query': query,'fields': ['name', 'summary', 'content'],}}, size=5, from_=from_)return render_template('index.html', results=results['hits']['hits'],query=query, from_=from_,total=results['hits']['total']['value'])
此处页面大小现已硬编码为 5(你可以随意使用您喜欢的任何其他数字)。 假定 from_ 参数作为提交表单中的附加字段给出,但该字段被认为是可选的,不存在时默认为 0。
index.html 中可用的搜索表单没有 from_ 字段,因此常规搜索将始终从第一个结果开始。 该模板显示有关所显示结果范围以及总数的信息。 以下是使用模板表达式完成此操作的方法:
<div class="col-sm-auto my-auto">Showing results {{ from_ + 1 }}-{{ from_ + results|length }} out of {{ total }}.
</div>
该模板还包括显示分页按钮以在结果列表中向前或向后移动的逻辑。 这是 “Previous results” 按钮的实现:
{% if from_ > 0 %}<div class="col-sm-auto my-auto"><a href="javascript:history.back(1)" class="btn btn-primary">← Previous page</a></div>
{% endif %}
正如您所看到的,只有当 from_ 大于零时,“Previous page” 按钮才会呈现到页面。 该按钮的实现使用浏览器的历史 API 来返回一页。
“Next page” 按钮有一个更有趣的实现:
{% if from_ + results|length < total %}<div class="col-sm-auto my-auto"><form method="POST"><input type="hidden" name="query" value="{{ query }}"><input type="hidden" name="from_" value="{{ from_ + results|length }}"><button type="submit" class="btn btn-primary">Next page →</button></form></div>
{% endif %}
该按钮实际上并不是一个独立的按钮,而是一个完整的表单,除了按钮之外还有两个隐藏字段。 该表单与主搜索表单类似,但包含可选的 from_ 字段,调整为指向下一页结果。 单击此按钮时,Flask 应用程序将从该备用表单接收搜索请求,该表单使用相同的文本查询,但使用非零的 from_ 值。
通过这种小而巧妙的分页实现,你将能够浏览多页结果。
过滤 - Filters
许多应用程序需要让用户能够自定义查询,以补充搜索查询本身的功能。 在本章中,你将学习过滤,这是一种技术,可以指定仅对满足给定条件的索引中包含的文档子集执行搜索查询。
布尔查询简介
在实现过滤器之前,你必须了解复合查询是如何在 Elasticsearch 中实现的。
复合查询允许应用程序组合两个或多个单独的查询,以便它们一起执行,并在适当的情况下返回一组组合结果。 在 Elasticsearch 中创建复合查询的标准方法是使用布尔查询。
布尔查询充当两个或多个单独查询或子句的包装器。 有四种不同的方式来组合查询:
- bool.must:子句必须匹配。 如果给出多个子句,则所有子句都必须匹配(类似于 AND 逻辑运算)。
- bool.should:当不带 must 使用时,至少一个子句应该匹配(类似于 OR 逻辑运算)。 当与 must 结合使用时,每个匹配子句都会提高文档的相关性得分。
- bool.filter:只有与子句匹配的文档才被视为搜索结果候选。
- bool.must_not:只有与子句不匹配的文档才被视为搜索结果候选。
有关布尔查询的更多描述,请参阅文章 “开始使用 Elasticsearch (2)”。
正如你可能从上面猜到的那样,布尔查询涉及相当多的复杂性,并且可以通过多种方式使用。 在本章中,你将学习如何将前面章节中实现的多重匹配全文搜索子句与将结果限制为一类文档的过滤器相结合。 回想一下,本教程使用的数据集包含一个 category 字段,可以设置为 sharepoint、teams 或 github。
向查询添加过滤器
当前在教程应用程序中实现的多重匹配查询使用以下结构:
{'multi_match': {'query': "query text here",'fields': ['name', 'summary', 'content'],}
}
要添加将此搜索限制为特定类别的过滤器,必须按如下方式扩展查询:
{'bool': {'must': [{'multi_match': {'query': "query text here",'fields': ['name', 'summary', 'content'],}}],'filter': [{'term': {'category.keyword': {'value': "category to filter"}}}]}
}
让我们详细看看该查询中的新组件。
首先,multi_match 查询已移至 bool.must 子句内。 bool.must 子句通常是定义基本查询的地方。 请注意,must 接受要搜索的查询列表,因此这允许在需要时组合多个基本级查询。
过滤是在 bool.filter 部分中使用新的查询类型(term 查询)实现的。 对过滤器使用 match 或 multi_match 查询并不是一个好主意,因为这些是全文搜索查询。 为了过滤的目的,查询必须为每个文档返回绝对正确或错误的答案,而不是像匹配查询那样返回相关性分数。
Term 查询对给定字段中的值执行精确搜索。 这种类型的查询对于搜索标识符、标签、标记或本例中的类别很有用。
此查询不适用于为全文搜索建立索引的字段。 字符串字段被分配为默认的 text 类型,并在索引之前对其内容进行分析并分成单独的单词。 Elasticsearch 为字符串字段分配了辅助类型的 keyword 字段,该关键字将字段内容作为一个整体进行索引,使它们更适合使用术语(term)查询进行过滤。 通过在查询的过滤器部分中使用 category.keyword 的字段名称,将使用该字段的 keyword 类型变体,而不是默认的 text 变体。
更多有关 text 及 keyword 之间的区别,请详细阅读文章 “Elasticsearch:Text vs. Keyword - 它们之间的差异以及它们的行为方式”。
指定过滤器
在实现过滤查询之前,需要添加一种方式供最终用户输入所需的过滤器。 本教程中实现的解决方案将在搜索查询的文本中查找 “category:<category-name>” 模式。 让我们向 add.py 添加一个名为 extract_filters() 的函数来查找过滤器表达式:
def extract_filters(query):filter_regex = r'category:([^\s]+)\s*'m = re.search(filter_regex, query)if m is None:return {}, query # no filtersfilters = {'filter': [{'term': {'category.keyword': {'value': m.group(1)}}}]}query = re.sub(filter_regex, '', query).strip()return filters, query
该函数接受用户输入的查询,并返回一个元组,其中包含在查询中找到的过滤器以及删除过滤器后修改后的查询。 为了查找过滤模式,它使用正则表达式。 如果需要,该功能可以通过附加过滤器进行扩展。
为了更好地理解此功能的工作原理,请启动 Python 会话(确保首先激活虚拟环境)并运行以下代码:
实施过滤搜索
剩下要做的就是更改 handle_search() 函数以发送更新的查询,该查询将全文搜索表达式与过滤器(如果用户给出了过滤器)组合在一起。 以下是该函数的新版本:
@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': {'multi_match': {'query': parsed_query,'fields': ['name', 'summary', 'content'],}},**filters}}, size=5, from_=from_)return render_template('index.html', results=results['hits']['hits'],query=query, from_=from_,total=results['hits']['total']['value'])
查询现已更改为发送 bool 表达式,并且搜索表达式已移至其下方的 must 部分内。 extract_filters() 函数以需要发送到 Elasticsearch 的形式返回查询的过滤器部分,因此它也被插入到查询字典中的顶级 bool 键下。
尝试搜索查询(例如 work from home Category:sharepoint)以查看如何仅返回给定类别 (category) 的文档。
从上面的结果中,我们可以看出来所有的文档的 Category 都是 sharepoint。
Match-all 查询
在转到新主题之前,请尝试在搜索查询文本字段中仅输入过滤器,例如 category:github。 不幸的是,这不会返回任何结果,但在这种情况下的预期行为是接收与请求的类别匹配的所有结果。
发生的情况是 extract_filters() 函数返回一个元组,其中第一个元素中包含过滤器,第二个元素中包含空查询字符串。 match_all 查询接收空字符串,并返回空结果列表,因为没有任何内容与空字符串匹配。
为了解决这种特殊情况,当搜索文本为空时,可以将 multi_match 查询替换为 match_all。 下面的 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 = {'must': {'multi_match': {'query': parsed_query,'fields': ['name', 'summary', 'content'],}}}else:search_query = {'must': {'match_all': {}}}results = es.search(query={'bool': {**search_query,**filters}}, size=5, from_=from_)return render_template('index.html', results=results['hits']['hits'],query=query, from_=from_,total=results['hits']['total']['value'])
在此版本中,你可以询问与某个类别匹配的所有文档。 请注意,所有返回的结果都具有相同的 1.0 分数,因为没有搜索词来计算分数。
恭喜,你已完成本教程的全文搜索部分! 单击此处查看到目前为止教程搜索应用程序的状态。你可以使用如下的命令来下载代码:
git clone https://github.com/liu-xiao-guo/search-tutorial-1
相关文章:

Elasticsearch:Serarch tutorial - 使用 Python 进行搜索 (二)
这个是继上一篇文章 “Elasticsearch:Serarch tutorial - 使用 Python 进行搜索 (一)” 的续篇。在今天的文章中,我们接着来完成如何进行分页及过滤。 分页 - pagination 应用程序处理大量结果通常是不切实际的。 因此࿰…...
力扣labuladong——一刷day84
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、力扣743. 网络延迟时间 前言 Dijkstra 算法(一般音译成迪杰斯特拉算法)无非就是一个 BFS 算法的加强版,它们都是从二叉…...

Linux环境vscode clang-format格式化:vscode clang format command is not available
问题现象 vscode安装了clang-format插件,但是使用就报错 问题原因 设置中配置的clang-format插件工具路径不正确。 解决方案 确认本地安装了clang-format工具:终端输入clang-format(也可能是clang-format-13等版本,建议tab自…...

【KingbaseES】实现MySql函数WEEKS_BETWEEN
WEEKS_BETWEEN CREATE OR REPLACE FUNCTION weeks_between(start_date date, end_date date) RETURNS integer AS $$ BEGIN RETURN EXTRACT(WEEK FROM end_date) - EXTRACT(WEEK FROM start_date); END; $$ LANGUAGE plpgsql IMMUTABLE;结果展示...

@Scheduled定时任务现状与改进
项目场景: 定时任务现状:每个项目都会有一些配置信息,这些信息我们是都放在一个配置服务中,这个服务会定时从配置表中加载所有配置存入本地JVM内存,以供调用方获取(调用方集成了配置服务的SDK,…...

python+selenium爬虫笔记
本文只是做例子,具体网站路径麻烦你们换下,还有xpath路径也换下 一、安装所需要的组件(此处采用谷歌) 1、安装驱动 查看你的浏览器版本,去安装对应的版本 下载驱动 下载驱动路径 之前版本的 输入这个路径下载下来解压…...

【LMM 009】MiniGPT-4:使用 Vicuna 增强视觉语言理解能力的多模态大模型
论文描述:MiniGPT-4: Enhancing Vision-Language Understanding with Advanced Large Language Models 论文作者:Deyao Zhu∗ Jun Chen∗ Xiaoqian Shen Xiang Li Mohamed Elhoseiny 作者单位:King Abdullah University of Science and Techn…...

SpringBoot学习(三)-整合JDBC、Druid、MyBatis
注:此为笔者学习狂神说SpringBoot的笔记,其中包含个人的笔记和理解,仅做学习笔记之用,更多详细资讯请出门左拐B站:狂神说!!! 一、整合JDBC使用(理解) 创建项目 勾选依赖启动器 查看依赖 …...

如何选择合适的语音呼叫中心?
市场上不同的语音呼叫中心提供商,都有其独特的优势和不足。企业在选择语音呼叫中心服务公司时,主要考虑以下因素:服务质量、价格、技术支持、客户支持等。 首先,服务质量是选择语音呼叫中心需关注的最重要因素之一。 为确保语音…...

使用qtquick调用python程序
一. 内容简介 使用qtquick调用python程序 二. 软件环境 2.1vsCode 2.2Anaconda version: conda 22.9.0 2.3pytorch 安装pytorch(http://t.csdnimg.cn/GVP23) 2.4QT 5.14.1 新版QT6.4,,6.5在线安装经常失败,而5.9版本又无法编译64位程序…...

【Axure高保真原型】树形表格_多选效果
今天和大家分享树形表格_多选效果的原型模板,点击树的箭头可以展开或者收起子节点,点击多选按钮可以选中或取消选择该行以及子级行内容,同时反选父级行内容,父级行内容能根据子级选中的数量自动反选,包括全选、半选和未…...

【Filament】加载obj和fbx模型
1 前言 3D 模型的常用格式主要有 obj、fbx、gltf 等,Filament 中的 filamesh.exe 工具可以将 obj、fbx 格式转换为 filamesh 格式,然后再加载显示。对于 gltf 格式模型,可以通过 ModelViewer 加载显示,这不在本文的讨论范围内。 1…...
[USACO04OPEN] The Cow Lineup
题目描述 约翰的 N ( 1 ≤ N ≤ 100000 ) N ( 1 \leq N \leq 100000 ) N(1≤N≤100000) 只奶牛站成了一列。每只奶牛都写有一个号牌,表示她的品种,号牌上的号码在 1 … K &#x…...
软件工具集合
代码文档自动生成工具: Doxygen download 软件分析工具: perf gdb flamegraph 代码量统计: vscode插件:VS Code Counter 代码备注 vsocde插件: Line Note...

C#利用openvino部署PP-TinyPose人体姿态识别
【官方框架地址】 github.com/PaddlePaddle/PaddleDetection 【算法介绍】 关键点检测算法往往需要部署在轻量化、边缘端设备上,因此长期以来都存在一个难题:精度高、速度则慢、算法体积也随之增加。而PP-TinyPose的出世彻底打破了这个僵局,…...

MindSpore Serving与TGI框架 の 对比
一、MindSpore Serving MindSpore Serving是一款轻量级、高性能的服务工具,帮助用户在生产环境中高效部署在线推理服务。 使用MindSpore完成模型训练>导出MindSpore模型,即可使用MindSpore Serving创建该模型的推理服务。 MindSpore Serving包含以…...

两阶段提交协议三阶段提交协议
两阶段提交协议 分布式事务是指会涉及到操作多个数据库的事务,在分布式系统中,各个节点之间在物理上相互独立,通过网络进行沟通和协调。 XA 就是 X/Open DTP 定义的交易中间件与数据库之间的接口规范(即接口函数),交易…...
6-Docker Compose-tomcat application(指定官方镜像)
1.创建docker-compose.yml文件,添加如下内容并保存 vim docker-compose.yml [root@centos79 ~]# cat docker-compose.yml #yml文件 version: 3 #版本号,默认为3 services:tomcat-ztj: #定…...
宝塔安装的imagemagick不能用,必须自己手动安装
1 安装 用composer安装 2 宝塔安装的imagemagick不能用,必须自己手动安装(3.4.3版本 php 7.3) 1 步骤: wget https://pecl.php.net/get/imagick-3.4.3.tgz tar -zxf imagick-3.4.3.tgz cd imagick-3.4.3 /www/server/php/73…...

解决在test以外的目录下导入junit无效
以上引用来自src目录下的文件,可以看到,和junit有关的导入都飘红,但明明junit已经被正确导入进了项目中。 再看右侧的Maven的依赖下方,junit的右边有一个很不起眼的(test) 这是因为junit作为测试框架,可能包含仅适用于…...

(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...
Java - Mysql数据类型对应
Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...

论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)
笔记整理:刘治强,浙江大学硕士生,研究方向为知识图谱表示学习,大语言模型 论文链接:http://arxiv.org/abs/2407.16127 发表会议:ISWC 2024 1. 动机 传统的知识图谱补全(KGC)模型通过…...

基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...
Mysql8 忘记密码重置,以及问题解决
1.使用免密登录 找到配置MySQL文件,我的文件路径是/etc/mysql/my.cnf,有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...

【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看
文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

C# 表达式和运算符(求值顺序)
求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如,已知表达式3*52,依照子表达式的求值顺序,有两种可能的结果,如图9-3所示。 如果乘法先执行,结果是17。如果5…...