居然是你

【搜索客社区日报】第1868期 (2024-07-26)

1、上半年拿到投资的 15 家 AI 搜索公司,他们都在做什么?
https://mp.weixin.qq.com/s/dSUEbsZ3gOmLEkQk--RJZw

2、最近硅谷人人都在讨论的GraphRAG到底是什么
https://mp.weixin.qq.com/s/Hx_nZItbwBL0XxckGnyXLg

3、减少 95% 资源的向量搜索 | 使用云搜索的 DiskANN
https://mp.weixin.qq.com/s/ddAv8X4qHKgfgpBkavLCPA

4、OpenSearch 向量检索和大模型方案深度解读
https://blog.51cto.com/u_15316473/8598095
 
🎉 活动预告:
【7月31日】第1期 | 2024 搜索客社区 Meetup 线上直播活动,主题:《Easysearch 结合大模型实现 RAG》
https://searchkit.cn/article/15209

编辑:Fred 
更多资讯:http://news.searchkit.cn
继续阅读 »
1、上半年拿到投资的 15 家 AI 搜索公司,他们都在做什么?
https://mp.weixin.qq.com/s/dSUEbsZ3gOmLEkQk--RJZw

2、最近硅谷人人都在讨论的GraphRAG到底是什么
https://mp.weixin.qq.com/s/Hx_nZItbwBL0XxckGnyXLg

3、减少 95% 资源的向量搜索 | 使用云搜索的 DiskANN
https://mp.weixin.qq.com/s/ddAv8X4qHKgfgpBkavLCPA

4、OpenSearch 向量检索和大模型方案深度解读
https://blog.51cto.com/u_15316473/8598095
 
🎉 活动预告:
【7月31日】第1期 | 2024 搜索客社区 Meetup 线上直播活动,主题:《Easysearch 结合大模型实现 RAG》
https://searchkit.cn/article/15209

编辑:Fred 
更多资讯:http://news.searchkit.cn 收起阅读 »

第1期 | 2024 搜索客社区 Meetup 线上直播活动,主题:Easysearch 结合大模型实现 RAG

2024 搜索客社区 Meetup 首期线上活动正式启动,本次活动由 搜索客社区、极限科技(INFINI Labs)联合举办,诚邀广大搜索技术开发者和爱好者参加交流学习。

活动时间:2024 年 7 月 31 日 19:30-20:30 (周三)
活动形式:微信视频号(极限实验室)直播
报名方式:关注或扫码海报中的二维码进行预约

活动海报

活动简介

在这个人工智能飞速发展的时代,ChatGPT 和 GPT-4 的出现无疑为人类带来了前所未有的震撼。我们不禁思考:通用人工智能的奇点是否真的即将来临?而最前沿的 AI 技术与最实用的落地应用之间的距离,又该如何缩短?

为了深入探讨这些问题,我们特别邀请到了极限科技(INFINI Labs)高级解决方案架构师、《老杨玩搜索》栏目 B 站 UP 主——杨帆先生,为我们带来一场主题为 “Easysearch 结合大模型实现 RAG” 的精彩演讲。

嘉宾介绍

杨帆,拥有十余年金融行业服务工作经验,熟悉 Linux、数据库、网络等领域。目前主要从事 Easysearch、Elasticsearch 等搜索引擎的技术支持工作,服务国内私有化部署的客户。他的丰富经验和深刻见解,将为我们揭开 AI 技术与实际应用之间的神秘面纱。

演讲主题

《Easysearch 结合大模型实现 RAG》

主题摘要

在本次演讲中,杨帆将跟大家分享和探讨以下几个方面:

  1. LangChain 简介:LangChain 的作用是什么?它由哪些组件构成,优势是什么。
  2. RAG 的背景及其局限性:RAG 出现以前的我们是如何获取信息的,RAG 解决了什么问题?它就是最终的答案了吗?
  3. LangChain 下的 RAG 工作流:在 LangChain 的框架下,实现 RAG 的步骤是怎样的。
  4. RAG Demo:使用 ollama 部署本地模型,利用 LangChain 集成 Easysearch 和 LLM , 开发 QA 问答系统

活动亮点

  • 前沿技术分享: 深入了解当前 AI 领域的最新动态和发展趋势。
  • 实战经验交流: 学习如何在实际工作中应用这些先进技术。
  • 互动问答环节: 与演讲嘉宾直接对话,解答你的疑惑。

参与有奖

本次直播活动中设置了随机抽奖环节,奖品为 INFINI Labs 周边纪念品,包括 T 恤、鸭舌帽、咖啡杯、指甲刀套件等等(图片仅供参考,款式、颜色与尺码随机)。

抽奖礼品

活动交流

活动交流群二维码 7 天内(8 月 1 日前)有效,如过期请添加小助手微信拉群。活动最新消息也会在群内及时同步,欢迎大家参与,记得先预约,精彩内容不错过!

活动交流

讲师招募

讲师招募

搜索客社区 Meetup 讲师持续招募中...

这是一个由搜索客社区精心组织策划的线下线上技术交流活动,我们诚挚邀请各位技术大咖、行业精英踊跃提交演讲议题。Meetup 活动将聚焦 AI 与搜索领域的最新动态,以及数据实时搜索分析、向量检索、技术实践与案例分析、日志分析、安全等领域的深度探讨。详情参见:http://cfp.searchkit.cn 。我们热切期待您的精彩分享!

关于 搜索客(SearchKit)社区

搜索客社区由 Elasticsearch 中文社区进行全新的品牌升级,以新的 Slogan:“搜索人自己的社区” 为宣言。汇集搜索领域最新动态、精选干货文章、精华讨论、文档资料、翻译与版本发布等,为广大搜索领域从业者提供更为丰富便捷的学习和交流平台。社区官网:https://searchkit.cn

Easysearch 有奖征文活动推荐

黑神话悟空

无论你是 Easysearch 的老用户,还是第一次听说这个名字,只要你对 INFINI Labs 旗下的 Easysearch 产品感兴趣,或者是希望了解 Easysearch,都可以参加这次活动。

详情查看:Easysearch 征文活动

继续阅读 »

2024 搜索客社区 Meetup 首期线上活动正式启动,本次活动由 搜索客社区、极限科技(INFINI Labs)联合举办,诚邀广大搜索技术开发者和爱好者参加交流学习。

活动时间:2024 年 7 月 31 日 19:30-20:30 (周三)
活动形式:微信视频号(极限实验室)直播
报名方式:关注或扫码海报中的二维码进行预约

活动海报

活动简介

在这个人工智能飞速发展的时代,ChatGPT 和 GPT-4 的出现无疑为人类带来了前所未有的震撼。我们不禁思考:通用人工智能的奇点是否真的即将来临?而最前沿的 AI 技术与最实用的落地应用之间的距离,又该如何缩短?

为了深入探讨这些问题,我们特别邀请到了极限科技(INFINI Labs)高级解决方案架构师、《老杨玩搜索》栏目 B 站 UP 主——杨帆先生,为我们带来一场主题为 “Easysearch 结合大模型实现 RAG” 的精彩演讲。

嘉宾介绍

杨帆,拥有十余年金融行业服务工作经验,熟悉 Linux、数据库、网络等领域。目前主要从事 Easysearch、Elasticsearch 等搜索引擎的技术支持工作,服务国内私有化部署的客户。他的丰富经验和深刻见解,将为我们揭开 AI 技术与实际应用之间的神秘面纱。

演讲主题

《Easysearch 结合大模型实现 RAG》

主题摘要

在本次演讲中,杨帆将跟大家分享和探讨以下几个方面:

  1. LangChain 简介:LangChain 的作用是什么?它由哪些组件构成,优势是什么。
  2. RAG 的背景及其局限性:RAG 出现以前的我们是如何获取信息的,RAG 解决了什么问题?它就是最终的答案了吗?
  3. LangChain 下的 RAG 工作流:在 LangChain 的框架下,实现 RAG 的步骤是怎样的。
  4. RAG Demo:使用 ollama 部署本地模型,利用 LangChain 集成 Easysearch 和 LLM , 开发 QA 问答系统

活动亮点

  • 前沿技术分享: 深入了解当前 AI 领域的最新动态和发展趋势。
  • 实战经验交流: 学习如何在实际工作中应用这些先进技术。
  • 互动问答环节: 与演讲嘉宾直接对话,解答你的疑惑。

参与有奖

本次直播活动中设置了随机抽奖环节,奖品为 INFINI Labs 周边纪念品,包括 T 恤、鸭舌帽、咖啡杯、指甲刀套件等等(图片仅供参考,款式、颜色与尺码随机)。

抽奖礼品

活动交流

活动交流群二维码 7 天内(8 月 1 日前)有效,如过期请添加小助手微信拉群。活动最新消息也会在群内及时同步,欢迎大家参与,记得先预约,精彩内容不错过!

活动交流

讲师招募

讲师招募

搜索客社区 Meetup 讲师持续招募中...

这是一个由搜索客社区精心组织策划的线下线上技术交流活动,我们诚挚邀请各位技术大咖、行业精英踊跃提交演讲议题。Meetup 活动将聚焦 AI 与搜索领域的最新动态,以及数据实时搜索分析、向量检索、技术实践与案例分析、日志分析、安全等领域的深度探讨。详情参见:http://cfp.searchkit.cn 。我们热切期待您的精彩分享!

关于 搜索客(SearchKit)社区

搜索客社区由 Elasticsearch 中文社区进行全新的品牌升级,以新的 Slogan:“搜索人自己的社区” 为宣言。汇集搜索领域最新动态、精选干货文章、精华讨论、文档资料、翻译与版本发布等,为广大搜索领域从业者提供更为丰富便捷的学习和交流平台。社区官网:https://searchkit.cn

Easysearch 有奖征文活动推荐

黑神话悟空

无论你是 Easysearch 的老用户,还是第一次听说这个名字,只要你对 INFINI Labs 旗下的 Easysearch 产品感兴趣,或者是希望了解 Easysearch,都可以参加这次活动。

详情查看:Easysearch 征文活动

收起阅读 »

【搜索客社区日报】第1867期 (2024-07-25)

1.Llama 3.1正式发布:4050亿参数模型开源,小扎:把开源进行到底
https://mp.weixin.qq.com/s/yXz5kuiUNQFdTUdHQITL2Q
2.开源仅 1 天就斩获近万星!超越 RAG、让大模型拥有超强记忆力的 Mem0 火了!
https://mp.weixin.qq.com/s/ZJUD2n5RZ6XCF3aZ53SpGw
3.MySQL新版恶性Bug,表太多就崩给你看
https://mp.weixin.qq.com/s/LTlR65SY7ZOpPFGH0kUsVg

编辑:Se7en  
更多资讯:http://news.searchkit.cn
继续阅读 »
1.Llama 3.1正式发布:4050亿参数模型开源,小扎:把开源进行到底
https://mp.weixin.qq.com/s/yXz5kuiUNQFdTUdHQITL2Q
2.开源仅 1 天就斩获近万星!超越 RAG、让大模型拥有超强记忆力的 Mem0 火了!
https://mp.weixin.qq.com/s/ZJUD2n5RZ6XCF3aZ53SpGw
3.MySQL新版恶性Bug,表太多就崩给你看
https://mp.weixin.qq.com/s/LTlR65SY7ZOpPFGH0kUsVg

编辑:Se7en  
更多资讯:http://news.searchkit.cn 收起阅读 »

搜索客社区日报 第1866期 (2024-07-24)

1.RAG 工业落地方案框架(Qanything、RAGFlow、FastGPT、智谱RAG)细节比对
https://mp.weixin.qq.com/s/z8CcFi03kQMGoEEQbuHzxw
2.Elasticsearch 中的位向量
https://blog.csdn.net/UbuntuTo ... 22765
3.介绍 Elasticsearch 中的 Learning to Tank - 学习排名
https://blog.csdn.net/UbuntuTo ... 64162

编辑:kin122 
更多资讯:http://news.searchkit.cn
继续阅读 »
1.RAG 工业落地方案框架(Qanything、RAGFlow、FastGPT、智谱RAG)细节比对
https://mp.weixin.qq.com/s/z8CcFi03kQMGoEEQbuHzxw
2.Elasticsearch 中的位向量
https://blog.csdn.net/UbuntuTo ... 22765
3.介绍 Elasticsearch 中的 Learning to Tank - 学习排名
https://blog.csdn.net/UbuntuTo ... 64162

编辑:kin122 
更多资讯:http://news.searchkit.cn 收起阅读 »

【搜索客社区日报】第1865期 (2024-07-23)



1. 没想到吧,我还能在树莓派上搭ES
https://medium.com/%40npan1990 ... 49770
2. 我是怎么在k8s上搭建elk全家的?
https://medium.com/%40degola/i ... bf199
3. 用RAG进一步提升AI powered searching的能力
https://medium.com/gitconnecte ... 4b1f8
编辑:斯蒂文
更多资讯:http://news.searchkit.cn
 
继续阅读 »


1. 没想到吧,我还能在树莓派上搭ES
https://medium.com/%40npan1990 ... 49770
2. 我是怎么在k8s上搭建elk全家的?
https://medium.com/%40degola/i ... bf199
3. 用RAG进一步提升AI powered searching的能力
https://medium.com/gitconnecte ... 4b1f8
编辑:斯蒂文
更多资讯:http://news.searchkit.cn
  收起阅读 »

【搜索客社区日报】第1864期 (2024-07-22)

1. 与 AI-RAN 联盟、3GPP 和 O-RAN 一起推动 6G 领域的 AI 驱动创新
https://developer.nvidia.com/b ... -ran/

2. 2024 年最值得关注的 8 个 AI 博客
https://www.greataiprompts.com ... logs/

3. 什么是 AI 代理?
https://www.technologyreview.c ... ents/

4. GPT-4o mini:推进成本效益型智能
https://openai.com/index/gpt-4 ... ence/

5. 2024 年数据库管理的未来
https://www.knowledgehut.com/b ... uture

编辑:Muse 
更多资讯:http://news.searchkit.cn
继续阅读 »
1. 与 AI-RAN 联盟、3GPP 和 O-RAN 一起推动 6G 领域的 AI 驱动创新
https://developer.nvidia.com/b ... -ran/

2. 2024 年最值得关注的 8 个 AI 博客
https://www.greataiprompts.com ... logs/

3. 什么是 AI 代理?
https://www.technologyreview.c ... ents/

4. GPT-4o mini:推进成本效益型智能
https://openai.com/index/gpt-4 ... ence/

5. 2024 年数据库管理的未来
https://www.knowledgehut.com/b ... uture

编辑:Muse 
更多资讯:http://news.searchkit.cn 收起阅读 »

【搜索客社区日报】第1863期 (2024-07-19)

1、TDBC 2024 可信数据库发展大会上,《搜索型数据库白皮书》正式发布,附下载地址
https://infinilabs.cn/blog/2024/news-20240718/

2、较 ClickHouse 降低 50% 成本,湖仓一体在B站的演进
https://dbaplus.cn/news-131-5889-1.html

3、LangChain 实战:RAG 遇上大模型,运维革命就开始了……
https://dbaplus.cn/news-73-5978-1.html

4、OpenSearch 的演进与语义检索技术革新
https://blog.csdn.net/kunpengt ... 16513

编辑:Fred 
更多资讯:http://news.searchkit.cn
继续阅读 »
1、TDBC 2024 可信数据库发展大会上,《搜索型数据库白皮书》正式发布,附下载地址
https://infinilabs.cn/blog/2024/news-20240718/

2、较 ClickHouse 降低 50% 成本,湖仓一体在B站的演进
https://dbaplus.cn/news-131-5889-1.html

3、LangChain 实战:RAG 遇上大模型,运维革命就开始了……
https://dbaplus.cn/news-73-5978-1.html

4、OpenSearch 的演进与语义检索技术革新
https://blog.csdn.net/kunpengt ... 16513

编辑:Fred 
更多资讯:http://news.searchkit.cn 收起阅读 »

【搜索客社区日报】第1862期 (2024-07-18)

1.推动 AI 革命:PyTorch 纪录片
https://mp.weixin.qq.com/s/lpT-8yQA8wAcxdjuBc88Ew
2.AIGC 提示词可视化编辑器 OPS
https://github.com/Moonvy/OpenPromptStudio
3.Facebook 为什么要弃用 Git?
https://mp.weixin.qq.com/s/n2UVEx8giKROJR9NWZB8pA
4.机场出租车恶性循环与国产数据库怪圈
https://mp.weixin.qq.com/s/uccjOkAR1zgur6tftHkzMg
5.被AI加持后的夸克,强大的让我有些陌生
https://mp.weixin.qq.com/s/RZ6J3v79bLOv6vhAm4nYLw

编辑:Se7en  
更多资讯:http://news.searchkit.cn
继续阅读 »
1.推动 AI 革命:PyTorch 纪录片
https://mp.weixin.qq.com/s/lpT-8yQA8wAcxdjuBc88Ew
2.AIGC 提示词可视化编辑器 OPS
https://github.com/Moonvy/OpenPromptStudio
3.Facebook 为什么要弃用 Git?
https://mp.weixin.qq.com/s/n2UVEx8giKROJR9NWZB8pA
4.机场出租车恶性循环与国产数据库怪圈
https://mp.weixin.qq.com/s/uccjOkAR1zgur6tftHkzMg
5.被AI加持后的夸克,强大的让我有些陌生
https://mp.weixin.qq.com/s/RZ6J3v79bLOv6vhAm4nYLw

编辑:Se7en  
更多资讯:http://news.searchkit.cn 收起阅读 »

Easysearch 新特性:写入限流功能介绍

背景

在 Easysearch 的各种使用场景中,高写入吞吐量的场景占了很大一部分,由此也带来了一些使用上的问题,很多用户由于使用经验不足,对集群的写入压测进行的不够充分,不能很好的规划集群的写入量。

导致经常发生以下问题:

  • 写入吞吐量过大对内存影响巨大,引发节点 OOM,节点掉线问题。
  • 对 CPU 和内存的占用严重影响了其他的查询业务的响应。
  • 以及磁盘 IO 负载增加,挤占集群的网络带宽等问题。

之前就有某金融保险类客户遇到了因业务端写入量突然猛增导致数据节点不停的 Full GC,进而掉入了不停的掉线,上线,又掉线的恶性循环中。当时只能建议用户增加一个类似“挡板”的服务,在数据进入到集群之前进行拦截,对客户端写入进行干预限流:

这样做虽然有效,但是也增加了整个系统的部署复杂性,提高了运维成本。

根据客户的实际场景,Easysearch 从 1.8.0 版本开始引入了节点和 Shard 级别的限流功能,不用依赖第三方就可以限制写入压力,并在 1.8.2 版本增加了索引级别的写入限流。 注意:所有写入限流都是针对各数据节点的 Primary Shard 写入进行限流的,算上副本的话吞吐量要乘以 2。

限流示意图:

下面是限流前后相同数据节点的吞吐量和 CPU 对比:

测试环境:

ip       name   http          port version role master
10.0.0.3 node-3 10.0.0.3:9209 9303 1.8.0   dimr -
10.0.0.3 node-4 10.0.0.3:9210 9304 1.8.0   im   -
10.0.0.3 node-2 10.0.0.3:9208 9302 1.8.0   dimr -
10.0.0.3 node-1 10.0.0.3:9207 9301 1.8.0   dimr *

测试索引配置:

PUT test_0
{
  "settings": {
    "number_of_replicas": 1,
    "number_of_shards": 3
  }
}

压测工具:采用极限科技的 INFINI Loadgen 压测,这款压测工具使用简单,可以方便对任何支持 Rest 接口的库进行压测。

压测命令:

 ./loadgen-linux-amd64 -d 180 -c 10 -config loadgen-easy-1.8.yml

压测 180 秒,10 个并发,每个 bulk 请求 5000 条。

节点级别限流

通过 INFINI Console 监控指标可以看到,限流之前的某个数据节点,CPU 占用 10%,每秒写入 40000 条左右:

在 Cluster Settings 里配置,启用节点级别限流,限制每个节点的每秒最大写入 10000 条,并在默认的 1 秒间隔内进行重试,超过默认间隔后直接拒绝。

PUT _cluster/settings
{
  "transient": {
    "cluster.throttle.node.write": true,
    "cluster.throttle.node.write.max_requests": 10000,
    "cluster.throttle.node.write.action": "retry"
  }
}

限流后,CPU 占用降低了约 50%,算上副本一共 20000 条每秒:

Shard 级别限流

设置每个分片最大写入条数为 2000 条每秒

PUT _cluster/settings
{
  "transient": {
    "cluster.throttle.shard.write": true,
    "cluster.throttle.shard.write.max_requests": 2000,
    "cluster.throttle.shard.write.action": "retry"
  }
}

集群级别的监控,同样是只针对主 Shard。

从 Console 的监控指标可以看出,索引 test_0 的 Primary indexing 维持在 6000 左右,正好是 3 个主分片限制的 2000 的写入之和。

再看下数据节点监控,Total Shards 表示主分片和副本分片的写入总和即 4000,单看主分片的话,正好是 2000.

索引级别限流

有时,集群中可能某个索引的写入吞吐过大而影响了其他业务,也可以针对特定的索引配置写入限制。 可以在索引的 Settings 里设置当前索引每秒写入最大条数为 6000:

PUT test_0
{
  "settings": {
    "number_of_replicas": 1,
    "number_of_shards": 3,
    "index.throttle.write.max_requests": 6000,
    "index.throttle.write.action": "retry",
    "index.throttle.write.enable": true
  }
}

下图索引的 Primary indexing 在 6000 左右,表示索引的所有主分片的写入速度限制在了 6000。

总结

通过本次测试对比,可以看出限流的好处:

  1. 有效控制写入压力: 写入限流功能能够有效限制每个节点和每个 Shard 的写入吞吐量,防止因写入量过大而导致系统资源被过度消耗的问题。

  2. 降低系统资源占用: 在限流前,某数据节点的 CPU 占用率约为 10%。限流后,CPU 占用率显著降低至约 5%,减少了约 50%。这表明在高并发写入场景下,写入限流功能显著降低了系统的 CPU 负载。

  3. 提高系统稳定性: 通过控制写入吞吐量,避免了频繁的 Full GC 和节点掉线问题,从而提升了系统的整体稳定性和可靠性。

  4. 保障查询业务性能: 写入限流功能减少了写入操作对 CPU 和内存的占用,确保其他查询业务的响应性能不受影响。

综上所述,写入限流功能在高并发写入场景下表现出色,不仅有效控制了写入压力,还显著降低了系统资源占用,从而提高了系统的稳定性和查询业务的性能。

关于 Easysearch 有奖征文活动

黑神话悟空

无论你是 Easysearch 的老用户,还是第一次听说这个名字,只要你对 INFINI Labs 旗下的 Easysearch 产品感兴趣,或者是希望了解 Easysearch,都可以参加这次活动。

详情查看:Easysearch 征文活动

作者:张磊

原文:https://infinilabs.cn/blog/2024/easysearch-new-feature-write-throttling-introduction/

继续阅读 »

背景

在 Easysearch 的各种使用场景中,高写入吞吐量的场景占了很大一部分,由此也带来了一些使用上的问题,很多用户由于使用经验不足,对集群的写入压测进行的不够充分,不能很好的规划集群的写入量。

导致经常发生以下问题:

  • 写入吞吐量过大对内存影响巨大,引发节点 OOM,节点掉线问题。
  • 对 CPU 和内存的占用严重影响了其他的查询业务的响应。
  • 以及磁盘 IO 负载增加,挤占集群的网络带宽等问题。

之前就有某金融保险类客户遇到了因业务端写入量突然猛增导致数据节点不停的 Full GC,进而掉入了不停的掉线,上线,又掉线的恶性循环中。当时只能建议用户增加一个类似“挡板”的服务,在数据进入到集群之前进行拦截,对客户端写入进行干预限流:

这样做虽然有效,但是也增加了整个系统的部署复杂性,提高了运维成本。

根据客户的实际场景,Easysearch 从 1.8.0 版本开始引入了节点和 Shard 级别的限流功能,不用依赖第三方就可以限制写入压力,并在 1.8.2 版本增加了索引级别的写入限流。 注意:所有写入限流都是针对各数据节点的 Primary Shard 写入进行限流的,算上副本的话吞吐量要乘以 2。

限流示意图:

下面是限流前后相同数据节点的吞吐量和 CPU 对比:

测试环境:

ip       name   http          port version role master
10.0.0.3 node-3 10.0.0.3:9209 9303 1.8.0   dimr -
10.0.0.3 node-4 10.0.0.3:9210 9304 1.8.0   im   -
10.0.0.3 node-2 10.0.0.3:9208 9302 1.8.0   dimr -
10.0.0.3 node-1 10.0.0.3:9207 9301 1.8.0   dimr *

测试索引配置:

PUT test_0
{
  "settings": {
    "number_of_replicas": 1,
    "number_of_shards": 3
  }
}

压测工具:采用极限科技的 INFINI Loadgen 压测,这款压测工具使用简单,可以方便对任何支持 Rest 接口的库进行压测。

压测命令:

 ./loadgen-linux-amd64 -d 180 -c 10 -config loadgen-easy-1.8.yml

压测 180 秒,10 个并发,每个 bulk 请求 5000 条。

节点级别限流

通过 INFINI Console 监控指标可以看到,限流之前的某个数据节点,CPU 占用 10%,每秒写入 40000 条左右:

在 Cluster Settings 里配置,启用节点级别限流,限制每个节点的每秒最大写入 10000 条,并在默认的 1 秒间隔内进行重试,超过默认间隔后直接拒绝。

PUT _cluster/settings
{
  "transient": {
    "cluster.throttle.node.write": true,
    "cluster.throttle.node.write.max_requests": 10000,
    "cluster.throttle.node.write.action": "retry"
  }
}

限流后,CPU 占用降低了约 50%,算上副本一共 20000 条每秒:

Shard 级别限流

设置每个分片最大写入条数为 2000 条每秒

PUT _cluster/settings
{
  "transient": {
    "cluster.throttle.shard.write": true,
    "cluster.throttle.shard.write.max_requests": 2000,
    "cluster.throttle.shard.write.action": "retry"
  }
}

集群级别的监控,同样是只针对主 Shard。

从 Console 的监控指标可以看出,索引 test_0 的 Primary indexing 维持在 6000 左右,正好是 3 个主分片限制的 2000 的写入之和。

再看下数据节点监控,Total Shards 表示主分片和副本分片的写入总和即 4000,单看主分片的话,正好是 2000.

索引级别限流

有时,集群中可能某个索引的写入吞吐过大而影响了其他业务,也可以针对特定的索引配置写入限制。 可以在索引的 Settings 里设置当前索引每秒写入最大条数为 6000:

PUT test_0
{
  "settings": {
    "number_of_replicas": 1,
    "number_of_shards": 3,
    "index.throttle.write.max_requests": 6000,
    "index.throttle.write.action": "retry",
    "index.throttle.write.enable": true
  }
}

下图索引的 Primary indexing 在 6000 左右,表示索引的所有主分片的写入速度限制在了 6000。

总结

通过本次测试对比,可以看出限流的好处:

  1. 有效控制写入压力: 写入限流功能能够有效限制每个节点和每个 Shard 的写入吞吐量,防止因写入量过大而导致系统资源被过度消耗的问题。

  2. 降低系统资源占用: 在限流前,某数据节点的 CPU 占用率约为 10%。限流后,CPU 占用率显著降低至约 5%,减少了约 50%。这表明在高并发写入场景下,写入限流功能显著降低了系统的 CPU 负载。

  3. 提高系统稳定性: 通过控制写入吞吐量,避免了频繁的 Full GC 和节点掉线问题,从而提升了系统的整体稳定性和可靠性。

  4. 保障查询业务性能: 写入限流功能减少了写入操作对 CPU 和内存的占用,确保其他查询业务的响应性能不受影响。

综上所述,写入限流功能在高并发写入场景下表现出色,不仅有效控制了写入压力,还显著降低了系统资源占用,从而提高了系统的稳定性和查询业务的性能。

关于 Easysearch 有奖征文活动

黑神话悟空

无论你是 Easysearch 的老用户,还是第一次听说这个名字,只要你对 INFINI Labs 旗下的 Easysearch 产品感兴趣,或者是希望了解 Easysearch,都可以参加这次活动。

详情查看:Easysearch 征文活动

作者:张磊

原文:https://infinilabs.cn/blog/2024/easysearch-new-feature-write-throttling-introduction/

收起阅读 »

【搜索客社区日报】第1859期 (2024-07-15)

1. Easysearch 新特性:写入限流功能介绍
https://infinilabs.cn/blog/202 ... tion/

2. 中文大模型基准测评2024年上半年报告
https://report.oschina.net/api ... o.pdf

3. ClickHouse 24.6 版本发布说明
https://mp.weixin.qq.com/s/JrAikqoUMjHHuaLEHZptew

4. 斯坦福年度《人工智能指数报告》的十条重要结论
https://cn.weforum.org/agenda/ ... t-cn/

5. 面壁智能首席科学家刘知远:大模型的“摩尔定律”是模型知识密度持续增强 
https://www.tsinghua.edu.cn/info/1182/112713.htm

编辑:Muse
更多资讯:http://news.searchkit.cn
继续阅读 »
1. Easysearch 新特性:写入限流功能介绍
https://infinilabs.cn/blog/202 ... tion/

2. 中文大模型基准测评2024年上半年报告
https://report.oschina.net/api ... o.pdf

3. ClickHouse 24.6 版本发布说明
https://mp.weixin.qq.com/s/JrAikqoUMjHHuaLEHZptew

4. 斯坦福年度《人工智能指数报告》的十条重要结论
https://cn.weforum.org/agenda/ ... t-cn/

5. 面壁智能首席科学家刘知远:大模型的“摩尔定律”是模型知识密度持续增强 
https://www.tsinghua.edu.cn/info/1182/112713.htm

编辑:Muse
更多资讯:http://news.searchkit.cn 收起阅读 »

搜索客社区日报 第1861期 (2024-07-17)

1.ES 慢上游响应问题优化在用户体验场景中的实践
https://mp.weixin.qq.com/s/L_inW26azHHmp7n3WVBrZg
2.Elasticsearch:介绍 retrievers - 搜索一切事物
https://blog.csdn.net/UbuntuTo ... 61405
3.LLM,GPT-1 — 生成式预训练 Transformer(搭梯)
https://towardsdatascience.com ... 96d3b
4.LLM,GPT-2——语言模型是无监督的多任务学习者(搭梯)
https://towardsdatascience.com ... 1f808
5.LLM,GPT-3:语言模型是小样本学习者(搭梯)
https://towardsdatascience.com ... 1b466


编辑:kin122 
更多资讯:http://news.searchkit.cn
继续阅读 »
1.ES 慢上游响应问题优化在用户体验场景中的实践
https://mp.weixin.qq.com/s/L_inW26azHHmp7n3WVBrZg
2.Elasticsearch:介绍 retrievers - 搜索一切事物
https://blog.csdn.net/UbuntuTo ... 61405
3.LLM,GPT-1 — 生成式预训练 Transformer(搭梯)
https://towardsdatascience.com ... 96d3b
4.LLM,GPT-2——语言模型是无监督的多任务学习者(搭梯)
https://towardsdatascience.com ... 1f808
5.LLM,GPT-3:语言模型是小样本学习者(搭梯)
https://towardsdatascience.com ... 1b466


编辑:kin122 
更多资讯:http://news.searchkit.cn 收起阅读 »

【搜索客社区日报】第1860期 (2024-07-16)

1. 可灵内测了,果断冲一波吧
https://klingai.kuaishou.com/

2. 一个还不错的语音复制模型
https://github.com/babysor/MockingBird
https://zhuanlan.zhihu.com/p/425692267

3. 一个算法比赛相关信息的收录站
https://oi-wiki.org/

编辑:斯蒂文
更多资讯:http://news.searchkit.cn
继续阅读 »
1. 可灵内测了,果断冲一波吧
https://klingai.kuaishou.com/

2. 一个还不错的语音复制模型
https://github.com/babysor/MockingBird
https://zhuanlan.zhihu.com/p/425692267

3. 一个算法比赛相关信息的收录站
https://oi-wiki.org/

编辑:斯蒂文
更多资讯:http://news.searchkit.cn 收起阅读 »

【搜索客社区日报】第1858期 (2024-07-12)

1、中文大模型基准测评上半年报告:GPT-4o 排名第一、通义千问 “国服最强”
https://www.oschina.net/news/301339

2、高级 RAG 检索策略之流程与模块化
https://mp.weixin.qq.com/s/WeAcAevUPemPKhQLhId3Vg

3、下一代 RAG 技术来了!微软正式开源 GraphRAG:大模型行业将迎来新的升级?
https://www.infoq.cn/article/sqaUMyNg6B8OrCcwg4vo

4、电商场景下 ES 搜索引擎的稳定性治理实践
https://mp.weixin.qq.com/s/fAgAgWWYJbbfcGGx1BpLsw

5、玩转 Easysearch 语法
https://infinilabs.cn/blog/202 ... ntax/

编辑:Fred 
更多资讯:http://news.searchkit.cn
继续阅读 »
1、中文大模型基准测评上半年报告:GPT-4o 排名第一、通义千问 “国服最强”
https://www.oschina.net/news/301339

2、高级 RAG 检索策略之流程与模块化
https://mp.weixin.qq.com/s/WeAcAevUPemPKhQLhId3Vg

3、下一代 RAG 技术来了!微软正式开源 GraphRAG:大模型行业将迎来新的升级?
https://www.infoq.cn/article/sqaUMyNg6B8OrCcwg4vo

4、电商场景下 ES 搜索引擎的稳定性治理实践
https://mp.weixin.qq.com/s/fAgAgWWYJbbfcGGx1BpLsw

5、玩转 Easysearch 语法
https://infinilabs.cn/blog/202 ... ntax/

编辑:Fred 
更多资讯:http://news.searchkit.cn 收起阅读 »

邀请函 | 极限科技全新搜索引擎 INFINI Pizza 亮相 2024 可信数据库发展大会!

过去一年,在全球 AI 浪潮和国家数据局成立的推动下,数据库产业变革不断、热闹非凡。2024 年,站在中国数字经济产业升级和数据要素市场化建设的时代交汇点上,“2024 可信数据库发展大会” 将于 2024 年 7 月 16-17 日在北京悠唐皇冠假日酒店隆重召开,大会将以 “自主、创新、引领” 为主题,以期进一步推动全球数据库产业进步,共同开创可信数据库行业的新时代。

届时,极限科技(INFINI Labs)创始人兼 CEO 曾勇 将于 7 月 17 日下午在 搜索与分析型数据库&多模数据库分论坛 发表主题演讲 《下一代万亿级实时搜索引擎的设计与思考》 ,主要介绍下一代纯实时搜索新引擎 INFINI Pizza 的设计思路与软件架构的思考以及复杂场景下的搜索需求和挑战,敬请期待!

关于极限科技(INFINI Labs)

INFINI Labs

极限科技,全称极限数据(北京)科技有限公司,是一家专注于实时搜索与数据分析的软件公司。旗下品牌极限实验室(INFINI Labs)致力于打造极致易用的数据探索与分析体验。

极限科技是一支年轻的团队,采用天然分布式的方式来进行远程协作,员工分布在全球各地,希望通过努力成为中国乃至全球企业大数据实时搜索分析产品的首选,为中国技术品牌输出添砖加瓦。

官网:https://www.infinilabs.cn

联系我们

继续阅读 »

过去一年,在全球 AI 浪潮和国家数据局成立的推动下,数据库产业变革不断、热闹非凡。2024 年,站在中国数字经济产业升级和数据要素市场化建设的时代交汇点上,“2024 可信数据库发展大会” 将于 2024 年 7 月 16-17 日在北京悠唐皇冠假日酒店隆重召开,大会将以 “自主、创新、引领” 为主题,以期进一步推动全球数据库产业进步,共同开创可信数据库行业的新时代。

届时,极限科技(INFINI Labs)创始人兼 CEO 曾勇 将于 7 月 17 日下午在 搜索与分析型数据库&多模数据库分论坛 发表主题演讲 《下一代万亿级实时搜索引擎的设计与思考》 ,主要介绍下一代纯实时搜索新引擎 INFINI Pizza 的设计思路与软件架构的思考以及复杂场景下的搜索需求和挑战,敬请期待!

关于极限科技(INFINI Labs)

INFINI Labs

极限科技,全称极限数据(北京)科技有限公司,是一家专注于实时搜索与数据分析的软件公司。旗下品牌极限实验室(INFINI Labs)致力于打造极致易用的数据探索与分析体验。

极限科技是一支年轻的团队,采用天然分布式的方式来进行远程协作,员工分布在全球各地,希望通过努力成为中国乃至全球企业大数据实时搜索分析产品的首选,为中国技术品牌输出添砖加瓦。

官网:https://www.infinilabs.cn

联系我们

收起阅读 »

玩转 Easysearch 语法

什么是 Easysearch

Elasticsearch 是一个基于 Apache Lucene 的开源分布式搜索和分析引擎,它被广泛应用于全文搜索、结构化搜索和分析等多种场景中。作为 Elasticsearch 的国产化替代方案,Easysearch 不仅保持了与原生 Elasticsearch 的高度兼容性,还在功能、性能、稳定性和扩展性方面进行了全面提升。对于开发团队来说,从 Elasticsearch 切换到 Easysearch 不需要做任何业务代码的调整,确保了无缝衔接和平滑迁移。

Easysearch 是基于 Elasticsearch 7.10.2 开源版本二次开发,所以支持 Elasticsearch 原始的 Query DSL 语法,基本的 SQL 语法,并且兼容现有 Elasticsearch 的 SDK,使得应用无需修改代码即可进行迁移。其平滑的迁移特性,如基于网关的无缝跨版本迁移与升级,提供了随时安全回退的能力。

在之前的文章中,我们已经介绍了 Easysearch 的搭建可视化工具的使用,今天我们将探讨 Easysearch 集群的基本概念和常用的 API。

Easysearch 集群的核心概念

Easysearch 集群由以下几个核心概念构成:

  1. 节点(Node):集群中的单个服务器,负责存储数据并参与集群的索引和搜索功能。
  2. 集群(Cluster):由一个或多个节点组成,拥有唯一的集群名,协同完成数据索引和查询任务。
  3. 索引(Index):存储相关数据的容器,类似于关系数据库中的数据库,一个索引包含多个文档。
  4. 文档(Document):索引中的基本数据单位,相当于关系数据库中的行。
  5. 字段(Field):文档中的一个属性,相当于数据库中的列。
  6. 分片(Shard):为了提高性能和扩展性,索引可以被分割成多个分片,每个分片是索引的一个部分。
  7. 副本(Replica):分片的副本,用于提高数据的可靠性和在节点出现故障时的可用性。

通过多个 API,例如 _cluster/health_cluster/stats,用户可以轻松查看集群的健康状态和详细信息,这些信息对于维护和优化 Easysearch 集群至关重要。

无论是在性能的提升,还是在功能的兼容性方面,Easysearch 都为用户提供了一个强大的搜索引擎平台,让从 Elasticsearch 到 Easysearch 的迁移变得无缝且高效。掌握其核心概念和 API 的使用,将帮助开发者更好地利用这些工具来构建和优化他们的搜索解决方案。

查看集群信息

在 Easysearch 中,可以通过多个 API 来查看集群的各种信息,包括集群的健康状况、节点信息和索引状态。以下是一些常用的查看集群信息的 API 和示例:

查看集群健康状况

_cluster/health API 可以查看集群的健康状态,包括集群是否处于正常状态、节点数量、分片状态等。

GET /_cluster/health

示例响应:

{
  "cluster_name": "my_cluster",
  "status": "green",
  "timed_out": false,
  "number_of_nodes": 3,
  "number_of_data_nodes": 3,
  "active_primary_shards": 5,
  "active_shards": 10,
  "relocating_shards": 0,
  "initializing_shards": 0,
  "unassigned_shards": 0,
  "delayed_unassigned_shards": 0,
  "number_of_pending_tasks": 0,
  "number_of_in_flight_fetch": 0,
  "task_max_waiting_in_queue_millis": 0,
  "active_shards_percent_as_number": 100.0
}

查看集群状态

_cluster/stats API 可以查看集群的详细状态,包括索引、节点、分片等信息。

GET /_cluster/stats

示例响应:

{
  "cluster_name": "my_cluster",
  "status": "green",
  "indices": {
    "count": 10,
    "shards": {
      "total": 20,
      "primaries": 10,
      "replication": 1.0,
      "index": {
        "shards": {
          "min": 1,
          "max": 5,
          "avg": 2.0
        }
      }
    }
  },
  "nodes": {
    "count": {
      "total": 3,
      "data": 3,
      "coordinating_only": 0,
      "master": 1,
      "ingest": 2
    },
    "os": {
      "available_processors": 12,
      "allocated_processors": 12
    },
    "process": {
      "cpu": {
        "percent": 10
      },
      "open_file_descriptors": {
        "min": 100,
        "max": 300,
        "avg": 200
      }
    }
  }
}

查看节点信息

_nodes API 可以查看集群中节点的详细信息,包括节点角色、IP 地址、内存使用情况等。

GET /_nodes

示例响应:

{
  "cluster_name": "my_cluster",
  "nodes": {
    "node_id_1": {
      "name": "node_1",
      "transport_address": "192.168.1.1:9300",
      "host": "192.168.1.1",
      "ip": "192.168.1.1",
      "roles": ["master", "data", "ingest"],
      "os": {
        "available_processors": 4,
        "allocated_processors": 4
      },
      "process": {
        "cpu": {
          "percent": 10
        },
        "open_file_descriptors": 200
      }
    },
    "node_id_2": {
      "name": "node_2",
      "transport_address": "192.168.1.2:9300",
      "host": "192.168.1.2",
      "ip": "192.168.1.2",
      "roles": ["data"],
      "os": {
        "available_processors": 4,
        "allocated_processors": 4
      },
      "process": {
        "cpu": {
          "percent": 15
        },
        "open_file_descriptors": 150
      }
    }
  }
}

查看索引状态

_cat/indices API 可以查看集群中所有索引的状态,包括文档数、存储大小、分片数等信息。

GET /_cat/indices?v

示例响应:

health status index   uuid                   pri rep docs.count docs.deleted store.size pri.store.size
green  open   index_1 SxNUd84vRl6QH5P7g0T4Vg   1   1          0            0       230b           230b
green  open   index_2 NxEYib4yToCnA1PpQ8P4Xw   5   1        100            1      10mb           5mb

这些 API 可以帮助你全面了解 Easysearch 集群的状态和健康状况,从而更好地管理和维护集群。

增删改查操作

在 Easysearch 中,增删改查操作是管理数据和索引的基本功能。以下是如何使用这些操作的详细示例。

创建索引

创建一个新的索引,并指定分片和副本的数量:

PUT /my_index
{
  "settings": {
    "number_of_shards": 3,
    "number_of_replicas": 2
  }
}

删除索引

删除一个不再需要的索引:

DELETE /my_index

添加文档

通过 POST 或 PUT 请求向索引中添加文档:

POST /my_index/_doc/1
{
  "name": "John Doe",
  "age": 30,
  "occupation": "Engineer"
}
PUT /my_index/_doc/1
{
  "name": "John Doe",
  "age": 30,
  "occupation": "Engineer"
}

POSTPUT 方法用于不同的操作,尽管它们都可以用于添加或更新文档,但它们的行为有所不同。

POST /my_index/_doc/1 方法用于创建或替换一个文档。如果指定的文档 ID 已经存在,POST 请求将更新整个文档(不会合并字段)。如果文档 ID 不存在,它将创建一个新的文档。


POST /my_index/_doc/1
{
  "name": "John Doe",
  "age": 30,
  "occupation": "Engineer"
}

PUT /my_index/_doc/1 方法通常用于创建一个新的文档,或者完全替换一个已存在的文档。与 POST 类似,如果指定的文档 ID 已经存在,PUT 请求将替换整个文档。

PUT /my_index/_doc/1
{
  "name": "John Doe",
  "age": 30,
  "occupation": "Engineer"
}

1.使用场景:

  • POST:更适合用于添加或部分更新文档,即使文档 ID 已经存在。
  • PUT:更适合用于创建或完全替换文档。

2.ID 自动生成:

  • POST 请求可以不提供文档 ID,此时 Easysearch 会自动生成一个文档 ID。
  • PUT 请求必须提供文档 ID,如果未提供,则会返回错误。

3.部分更新:

  • POST 请求可以用于部分更新(通过 _update API)。
  • PUT 请求用于完全替换文档,不支持部分更新。

如果文档 ID 已经存在,POSTPUT 都会覆盖整个文档,并且效果是一样的。但是,通常 POST 用于提交数据,而 PUT 用于上传和替换资源。

1.使用 POST 方法添加或更新文档:

POST /my_index/_doc/1
{
  "name": "John Doe",
  "age": 30,
  "occupation": "Engineer"
}

2.使用 PUT 方法添加或更新文档:

PUT /my_index/_doc/1
{
  "name": "John Doe",
  "age": 30,
  "occupation": "Engineer"
}

在这两个示例中,结果都是在索引 my_index 中创建或更新文档 ID 为 1 的文档。无论使用 POST 还是 PUT,如果文档 ID 已存在,都会覆盖原有的文档内容。

新建文档

使用 _create 方法新建文档,如果文档已经存在则返回错误:

PUT /my_index/_create/1
{
  "a": 1
}

如果尝试新建已存在的文档,将会出现如下错误:

{
  "error": {
    "root_cause": [
      {
        "type": "version_conflict_engine_exception",
        "reason": "[1]: version conflict, document already exists (current version [1])",
        "index_uuid": "1xWdHLTaTm6l6HbqACaIEA",
        "shard": "0",
        "index": "my_index"
      }
    ],
    "type": "version_conflict_engine_exception",
    "reason": "[1]: version conflict, document already exists (current version [1])",
    "index_uuid": "1xWdHLTaTm6l6HbqACaIEA",
    "shard": "0",
    "index": "my_index"
  },
  "status": 409
}

获取文档

通过 ID 获取文档的详细信息:

GET /my_index/_doc/1

更新文档

更新文档的特定字段,保留原有字段:

POST /my_index/_update/1
{
  "doc": {
    "age": 31
  }
}

删除文档

通过 ID 删除指定的文档:

DELETE /my_index/_doc/1

查询所有文档

查询索引中的所有文档:

GET /my_index/_search
{
  "query": {
    "match_all": {}
  }
}

这个是 《老杨玩搜索》中总结的图,可以作为“小抄”来记忆:

批量操作 (_bulk API)

_bulk API 用于在一次请求中执行多个索引、删除和更新操作,这对于批量处理大规模数据非常有用,可以显著提高性能和效率。以下是 _bulk API 的基本使用示例:

POST /my_index/_bulk
{ "index": { "_id": "1" } }
{ "name": "John Doe", "age": 30, "occupation": "Engineer" }
{ "index": { "_id": "2" } }
{ "name": "Jane Doe", "age": 25, "occupation": "Designer" }
{ "update": { "_id": "1" } }
{ "doc": { "age": 31 } }

_bulk API 的请求体由多个操作和文档组成。每个操作行包含一个动作描述行和一个可选的源文档行。动作描述行指明了操作的类型(例如,index、create、delete、update)以及操作的元数据。源文档行则包含了实际的数据。

每个操作之间需要用换行符分隔,并且请求体最后必须以换行符结尾。

POST /_bulk
{ "index": { "_index": "a", "_id": "1" } }
{ "name": "John Doe", "age": 30, "occupation": "Engineer" }
{ "index": { "_index": "b", "_id": "2" } }
{ "name": "Jane Doe", "age": 25, "occupation": "Designer" }
{ "update": { "_index": "a", "_id": "1" } }
{ "doc": { "age": 31 } }

分词器

在 Easysearch 中,分词器(Analyzer)用于将文本分解为词项(terms),是全文搜索和文本分析的基础。分词器通常由字符过滤器(Character Filters)、分词器(Tokenizer)和词项过滤器(Token Filters)组成。以下是关于分词器的详细介绍:

1.字符过滤器(Character Filters):在分词之前对文本进行预处理。例如,去除 HTML 标签,替换字符等。

2.分词器(Tokenizer):将文本分解为词项(tokens)。这是分词过程的核心。

3.词项过滤器(Token Filters):对词项进行处理,如小写化、去除停用词、词干提取等。

只有 text 字段支持全文检索,返回的结果根据相似度打分,我们一起看下

POST /index/_mapping
{
  "properties": {
    "content": {
      "type": "text",
      "analyzer": "ik_max_word",
      "search_analyzer": "ik_smart"
    }
  }
}

.POST /index/_mapping

  • 这个部分表示要向名为 index 的索引添加或更新映射设置。

2.“properties”

  • properties 定义了索引中文档的字段结构。在这个例子中,定义了一个名为 content 的字段。

3.“content”

  • 定义了名为 content 的字段。

4.“type”: “text”

type 字段指定 content 字段的数据类型为 texttext 类型适用于需要分词和全文搜索的字段。

5.“analyzer”: “ik_max_word”

analyzer 字段指定索引时使用的分词器为ik_max_wordik_max_word 是 IK 分词器中的一种,它会尽可能多地将文本分解为更多的词项。

6.“search_analyzer”: “ik_smart”

search_analyzer 字段指定搜索时使用的分词器为ik_smartik_smart 是 IK 分词器中的另一种,它会更智能地进行分词,以提高搜索的准确性。

当然,在设置这个 mapping 的时候可以使用同样的分词器,也可以使用不同的分词器。这里介绍下 IK 分词器:

  • IK 分词器是一种中文分词器,适用于中文文本的分词。IK 分词器有两种分词模式:ik_max_wordik_smart
    • ik_max_word:将文本尽可能多地切分成词项,适用于需要更高召回率的场景。
    • ik_smart:进行最智能的分词,适用于需要更高精度的搜索场景。

这个 DSL 的设置意味着,在向这个索引添加或更新文档时,content 字段的文本会使用ik_max_word 分词器进行分词处理,以确保文本被尽可能多地切分成词项。而在搜索时,content 字段的文本会使用ik_smart 分词器进行分词处理,以提高搜索的准确性和相关性。

以下是关于 standard,ik_smart,ik_max_word 这几个分词器的对比:

GET /_analyze
{
  "tokenizer": "standard",
  "text": "我,机器人"
}

GET /_analyze
{
  "tokenizer": "ik_smart",
  "text": "我,机器人"
}

GET /_analyze
{
  "tokenizer": "ik_max_word",
  "text": "我,机器人"
}

结果如下:

# GET /_analyze (standard)
{
  "tokens": [
    {
      "token": "我",
      "start_offset": 0,
      "end_offset": 1,
      "type": "<IDEOGRAPHIC>",
      "position": 0
    },
    {
      "token": "机",
      "start_offset": 2,
      "end_offset": 3,
      "type": "<IDEOGRAPHIC>",
      "position": 1
    },
    {
      "token": "器",
      "start_offset": 3,
      "end_offset": 4,
      "type": "<IDEOGRAPHIC>",
      "position": 2
    },
    {
      "token": "人",
      "start_offset": 4,
      "end_offset": 5,
      "type": "<IDEOGRAPHIC>",
      "position": 3
    }
  ]
}
# GET /_analyze(ik_smart)
{
  "tokens": [
    {
      "token": "我",
      "start_offset": 0,
      "end_offset": 1,
      "type": "CN_CHAR",
      "position": 0
    },
    {
      "token": "机器人",
      "start_offset": 2,
      "end_offset": 5,
      "type": "CN_WORD",
      "position": 1
    }
  ]
}
# GET /_analyze (ik_max_word)
{
  "tokens": [
    {
      "token": "我",
      "start_offset": 0,
      "end_offset": 1,
      "type": "CN_CHAR",
      "position": 0
    },
    {
      "token": "机器人",
      "start_offset": 2,
      "end_offset": 5,
      "type": "CN_WORD",
      "position": 1
    },
    {
      "token": "机器",
      "start_offset": 2,
      "end_offset": 4,
      "type": "CN_WORD",
      "position": 2
    },
    {
      "token": "人",
      "start_offset": 4,
      "end_offset": 5,
      "type": "CN_CHAR",
      "position": 3
    }
  ]
}

如果使用了不存在的分词器会出现这个错误。

{
  "error": {
    "root_cause": [
      {
        "type": "illegal_argument_exception",
        "reason": "failed to find global tokenizer under [simple]"
      }
    ],
    "type": "illegal_argument_exception",
    "reason": "failed to find global tokenizer under [simple]"
  },
  "status": 400
}

精确搜索/正则表达式搜索/通配符

在 Easysearch 中,精确搜索、正则表达式搜索和通配符搜索是三种不同的搜索方式,各有其应用场景和特点:

1.精确搜索 (Term Query)

  • 精确搜索用于查找与搜索词完全匹配的文档。
  • 不进行分词处理,通常用于关键字、ID、标签等字段的精确匹配。
  • 适用于结构化数据或不需要分词的字段(如数字、日期、布尔值等)。
{
  "query": {
    "term": {
      "status": "active"
    }
  }
}

2.正则表达式搜索 (Regexp Query)

  • 正则表达式搜索用于基于正则表达式模式匹配的文档搜索。
  • 支持复杂的字符串匹配模式,但性能可能较低,特别是当数据量较大时。
  • 适用于需要灵活且复杂匹配条件的搜索。
{
  "query": {
    "regexp": {
      "content": "Easysearch .*powerful"
    }
  }
}

3.通配符搜索 (Wildcard Query)

  • 通配符搜索用于通过通配符模式匹配文档。
  • 支持 ?(匹配单个字符)和 *(匹配零个或多个字符)。
  • 性能相对较差,因为通配符搜索可能需要扫描大量数据。
{
  "query": {
    "wildcard": {
      "username": "john*"
    }
  }
}
  • 精确搜索:用于需要绝对匹配特定词语或不需要分词的字段。例如,查找特定用户 ID 或状态。
  • 正则表达式搜索:用于需要复杂字符串模式匹配的场景,但要谨慎使用,避免性能问题。
  • 通配符搜索:用于简单模式匹配,但同样需要注意性能影响,尽量避免在大数据集上频繁使用。

接下来看这个例子,我们将使用批量导入数据,然后进行几种不同类型的查询,包括精确查询、通配符查询和正则表达式查询。

POST /users/_bulk
{ "index": { "_index": "users", "_id": 1 }}
{ "username": "john_doe", "status": "active", "email": "john.doe@example.com", "bio": "John loves Easysearch  and open-source technologies." }
{ "index": { "_index": "users", "_id": 2 }}
{ "username": "jane_doe", "status": "inactive", "email": "jane.doe@example.com", "bio": "Jane is a data scientist working with big data." }
{ "index": { "_index": "users", "_id": 3 }}
{ "username": "john_smith", "status": "active", "email": "john.smith@example.com", "bio": "John enjoys hiking and nature." }
{ "index": { "_index": "users", "_id": 4 }}
{ "username": "alice_jones", "status": "active", "email": "alice.jones@example.com", "bio": "Alice is a software engineer specialized in JavaScript." }
{ "index": { "_index": "users", "_id": 5 }}
{ "username": "bob_jones", "status": "inactive", "email": "bob.jones@example.com", "bio": "Bob is an AI enthusiast and machine learning expert." }

1.精确查询:查询状态为 “active” 的用户。

GET /users/_search
{
  "query": {
    "term": {
      "status": "active"
    }
  }
}

2.通配符查询:查询 bio 字段中包含 “John” 开头的词。

GET /users/_search
{
  "query": {
    "wildcard": {
      "bio": "John*"
    }
  }
}

3.正则表达式查询:查询用户名以 “john” 开头的用户

GET /users/_search
{
  "query": {
    "regexp": {
      "username": "john.*"
    }
  }
}

通过这些例子,你可以看到如何在 Easysearch 中使用批量导入数据,然后使用各种查询方法来检索特定条件的数据。这些查询方法可以帮助你高效地搜索和分析数据,以满足不同的业务需求。

这里同样是《老杨玩搜索》中总结的“小抄”来方便记忆:

多字段查询

在 Easysearch 中,多字段查询允许您在多个字段上同时执行搜索,以获取更精确的结果。最常用的多字段查询类型是 multi_match 查询。multi_match 查询是 match 查询的扩展,能够在多个字段中搜索指定的关键词。

multi_match 查询支持多种匹配模式,如 best_fieldsmost_fieldscross_fieldsphrasephrase_prefix。以下是各模式的简要介绍:

  • best_fields:默认模式,选择匹配度最高的字段。
  • most_fields:计算每个字段的匹配度,然后将匹配度相加。
  • cross_fields:将多个字段视为一个字段进行匹配,适用于分析文本被分散到多个字段的情况。
  • phrase:短语匹配,确保词项顺序与查询相同。
  • phrase_prefix:短语前缀匹配,允许词项的部分匹配。

我们先导入一些示例数据到一个索引 documents 中:

POST /documents/_bulk
{ "index": { "_id": 1 } }
{ "title": "Easysearch  Guide", "content": "This is an introductory guide to Easysearch ." }
{ "index": { "_id": 2 } }
{ "title": "Advanced Easysearch ", "content": "This guide covers advanced topics in Easysearch ." }
{ "index": { "_id": 3 } }
{ "title": "Easysearch  in Action", "content": "Practical guide to Easysearch  usage." }
{ "index": { "_id": 4 } }
{ "title": "Learning Easysearch ", "content": "Beginner's guide to learning Easysearch ." }

我们将使用 multi_match 查询在 titlecontent 字段中同时搜索关键词。

1.基本 multi_match 查询

POST /documents/_search
{
  "query": {
    "multi_match": {
      "query": "guide",
      "fields": ["title", "content"]
    }
  }
}

2.指定匹配模式为 best_fields

POST /documents/_search
{
  "query": {
    "multi_match": {
      "query": "guide",
      "fields": ["title", "content"],
      "type": "best_fields"
    }
  }
}

3.指定匹配模式为 most_fields

POST /documents/_search
{
  "query": {
    "multi_match": {
      "query": "guide",
      "fields": ["title", "content"],
      "type": "most_fields"
    }
  }
}

4.使用 cross_fields 模式

POST /documents/_search
{
  "query": {
    "multi_match": {
      "query": "Easysearch  guide",
      "fields": ["title", "content"],
      "type": "cross_fields"
    }
  }
}

5.短语匹配 (phrase)

POST /documents/_search
{
  "query": {
    "multi_match": {
      "query": "introductory guide",
      "fields": ["title", "content"],
      "type": "phrase"
    }
  }
}

6.短语前缀匹配 (phrase_prefix)

POST /documents/_search
{
  "query": {
    "multi_match": {
      "query": "introductory gui",
      "fields": ["title", "content"],
      "type": "phrase_prefix"
    }
  }
}
  • query:要搜索的关键词或短语。
  • fields:要搜索的字段列表,可以包含一个或多个字段。
  • type:指定匹配模式,默认为 best_fields。

使用 multi_match 查询,您可以在多个字段上同时执行搜索,获得更精确和全面的结果。通过指定不同的匹配模式,您可以调整查询行为以满足特定的搜索需求。无论是基本关键词匹配、短语匹配还是跨字段匹配,multi_match 查询都提供了强大的功能来处理复杂的搜索场景。

除此之外,还可以使用 boost 参数用于调整特定字段的权重,从而影响搜索结果的相关性评分。multi_match 查询支持为不同字段设置不同的 boost 值,以便在搜索结果中优先显示某些字段的匹配项。

布尔查询

布尔查询是 Easysearch 中非常强大且灵活的一种查询方式,它允许用户通过组合多个查询条件来实现复杂的搜索需求。布尔查询使用 bool 查询类型,可以包含以下几种子句:mustfiltermust_notshould。每种子句都有其特定的用途和语义。

1.must

  • 包含在 must 数组中的查询条件必须匹配,类似于逻辑上的 AND 操作。
  • 如果有多个条件,所有条件都必须满足,文档才会被包含在结果集中。

2.filter

  • 包含在 filter 数组中的查询条件必须匹配,但它不会影响评分。
  • filter 子句通常用于对性能要求较高的过滤操作,因为它不计算相关性评分。

3.must_not

  • 包含在 must_not 数组中的查询条件必须不匹配,类似于逻辑上的 NOT 操作。
  • 如果有任何一个条件匹配,文档就会被排除在结果集之外。

4.should

  • 包含在 should 数组中的查询条件至少匹配一个。
  • 如果布尔查询中没有 must 子句,则至少要匹配一个 should 子句。
  • should 子句在计算相关性评分时也有影响。

5.minimum_should_match

  • 指定 should 子句中至少需要满足的条件数量。

首先,我们需要创建一个名为 books 的索引,并定义它的映射(mappings)。映射用于指定每个字段的数据类型。在这个例子中,类别书名字段都被定义为 keyword 类型,这是因为我们需要进行精确匹配查询。

PUT /books
{
  "mappings": {
    "properties": {
      "类别": { "type": "keyword" },
      "书名": { "type": "keyword" }
    }
  }
}

接下来,我们使用批量操作(bulk API)将一些示例数据导入到 books 索引中。这些数据包括不同类别的书籍。

POST /books/_bulk
{ "index": { "_id": 1 } }
{ "类别": "文学", "书名": "我的阿勒泰" }
{ "index": { "_id": 2 } }
{ "类别": "文学", "书名": "平凡的世界" }
{ "index": { "_id": 3 } }
{ "类别": "科学", "书名": "时间简史" }
{ "index": { "_id": 4 } }
{ "类别": "文学", "书名": "百年孤独" }
{ "index": { "_id": 5 } }
{ "类别": "文学", "书名": "红楼梦" }

现在,我们使用布尔查询来搜索类别为“文学”并且书名为“我的阿勒泰”的文档。这里使用的是 must子句,表示查询结果必须满足所有条件。

POST /books/_search
{
  "query": {
    "bool": {
      "must": [
        { "term": { "类别": "文学" } },
        { "term": { "书名": "我的阿勒泰" } }
      ]
    }
  }
}

我们还可以使用 filter 子句来执行相同的查询。filter 子句用于过滤文档,且不会影响文档的相关性评分。这在不需要计算相关性评分时可以提高查询性能。

POST /books/_search
{
  "query": {
    "bool": {
      "filter": [
        { "term": { "类别": "文学" } },
        { "term": { "书名": "我的阿勒泰" } }
      ]
    }
  }
}

当我们执行上述查询时,期望返回的结果是 books 索引中类别为“文学”且书名为“我的阿勒泰”的文档。无论是使用 must 还是 filter 子句,结果应该都是:

{
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "hits": [
      {
        "_index": "books",
        "_id": "1",
        "_source": {
          "类别": "文学",
          "书名": "我的阿勒泰"
        }
      }
    ]
  }
}

POST /_search
{
  "query": {
    "bool": {
      "must": [
        { "term": { "user.id": "kimchy" } }
      ],
      "filter": [
        { "term": { "tags": "production" } }
      ],
      "must_not": [
        {
          "range": {
            "age": { "gte": 10, "lte": 20 }
          }
        }
      ],
      "should": [
        { "term": { "tags": "env1" } },
        { "term": { "tags": "deployed" } }
      ],
      "minimum_should_match": 1,
      "boost": 1.0
    }
  }
}
  • must 子句:必须匹配的条件,文档必须包含 user.idkimchy
  • filter 子句:过滤条件,文档必须包含 tagsproduction ,但不会影响评分。
  • must_not子句:不匹配的条件,文档的 age 字段不能在 10 到 20 之间。
  • should 子句:可选匹配条件,至少需要匹配一个 should 子句中的条件。这里要求 tags 字段匹配 env1deployed
  • minimum_should_match:至少需要匹配一个 should 子句中的条件。
  • boost:提升查询的整体评分。

为了展示这个 DSL ,我们需要创建一个索引并导入一些数据。假设我们要在 Easysearch 中创建一个索引 users ,并插入一些测试数据。

创建索引

PUT /users
{
  "mappings": {
    "properties": {
      "user.id": { "type": "keyword" },
      "tags": { "type": "keyword" },
      "age": { "type": "integer" }
    }
  }
}

批量导入数据

POST /users/_bulk
{ "index": { "_id": 1 } }
{ "user.id": "kimchy", "tags": ["production", "env1"], "age": 25 }
{ "index": { "_id": 2 } }
{ "user.id": "kimchy", "tags": ["production"], "age": 15 }
{ "index": { "_id": 3 } }
{ "user.id": "kimchy", "tags": ["deployed"], "age": 30 }
{ "index": { "_id": 4 } }
{ "user.id": "kimchy", "tags": ["test"], "age": 35 }
{ "index": { "_id": 5 } }
{ "user.id": "other", "tags": ["production"], "age": 25 }

接下来执行布尔查询:

POST /users/_search
{
  "query": {
    "bool": {
      "must": [
        { "term": { "user.id": "kimchy" } }
      ],
      "filter": [
        { "term": { "tags": "production" } }
      ],
      "must_not": [
        {
          "range": {
            "age": { "gte": 10, "lte": 20 }
          }
        }
      ],
      "should": [
        { "term": { "tags": "env1" } },
        { "term": { "tags": "deployed" } }
      ],
      "minimum_should_match": 1,
      "boost": 1.0
    }
  }
}

根据以上查询,预期返回的结果应该符合以下条件:

  1. user.id必须是 kimchy(由 must 子句决定)。
  2. tags 必须包含 production (由 filter 子句决定)。
  3. age 字段不在 10 到 20 之间(由 must_not 子句决定)。
  4. tags字段中至少包含 env1deployed 中的一个(由 should 子句和 minimum_should_match 参数决定)。
{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 1.3769134,
    "hits": [
      {
        "_index": "users",
        "_type": "_doc",
        "_id": "1",
        "_score": 1.3769134,
        "_source": {
          "user.id": "kimchy",
          "tags": ["production", "env1"],
          "age": 25
        }
      }
    ]
  }
}

SQL 搜索

Easysearch 直接支持 SQL 查询,无需额外安装插件,同时兼容 Elasticsearch 的 SQL 调用方式,还可以直接编写原生 SQL 查询。

以下是一些测试 SQL 语句的示例:

SELECT * FROM my_index;

SELECT * FROM my_index LIMIT 2;

SELECT * FROM my_index ORDER BY name;

SELECT name AS full_name, age FROM my_index WHERE age > 25;

SELECT name AS full_name, age FROM my_index WHERE age = 25;

SELECT * FROM my_index WHERE age IS NULL;

SELECT DISTINCT age FROM my_index;

SELECT MIN(age), MAX(age), AVG(age) FROM my_index;

SELECT age, COUNT(*) AS CNT FROM my_index GROUP BY age;

使用 Easysearch 执行 SQL 查询

Easysearch 提供了对直接使用 SQL 查询的支持。以下是如何在 Easysearch 中通过 POST 请求使用 _sql 端点进行查询的示例:

执行 SQL 查询非常简单,只需通过 POST 请求发送 SQL 查询即可。以下是一个示例:

POST /_sql
{
  "query": "SELECT name AS full_name, age FROM my_index WHERE age > 25"
}

你也可以规定返回 JSON 格式:

POST /_sql?format=json
{
  "query": "SELECT name AS full_name, age FROM my_index WHERE age > 25"
}

和 Elasticsearch 一样,Easysearch 允许你通过 POST 请求直接在集群上运行 SQL 查询,并返回查询结果。以下是一些常见的 SQL 查询示例及其对应的 POST 请求:

1.查询所有文档

POST /_sql
{
  "query": "SELECT * FROM my_index"
}

2.限制返回文档数

POST /_sql
{
  "query": "SELECT * FROM my_index LIMIT 2"
}

3.按字段排序

POST /_sql
{
  "query": "SELECT * FROM my_index ORDER BY name"
}

4.筛选条件查询

POST /_sql
{
  "query": "SELECT name AS full_name, age FROM my_index WHERE age > 25"
}

5.精确值查询

POST /_sql
{
  "query": "SELECT name AS full_name, age FROM my_index WHERE age = 25"
}

6.查询空值

POST /_sql
{
  "query": "SELECT * FROM my_index WHERE age IS NULL"
}

7.查询唯一值

POST /_sql
{
  "query": "SELECT DISTINCT age FROM my_index"
}

8.聚合函数查询

POST /_sql
{
  "query": "SELECT MIN(age), MAX(age), AVG(age) FROM my_index"
}

9.分组统计

POST /_sql
{
  "query": "SELECT age, COUNT(*) AS CNT FROM my_index GROUP BY age"
}

多表操作的 SQL 语句

以下是多表操作的 SQL 语句及其解释:

1.子查询

SELECT * FROM `table1` t1 WHERE t1.id IN (SELECT id FROM `table2`)

这个查询从 table1 中选择所有字段的记录,其中这些记录的 idtable2 表中也存在。

2.内连接

SELECT * FROM `table1` t1 JOIN `table2` t2 ON t1.id = t2.id

这个查询进行内连接,从 table1table2 中选择所有字段的记录,前提是 table1table2id 相等。

3.左连接

SELECT * FROM `table1` t1 LEFT JOIN `table2` t2 ON t1.id = t2.id

这个查询进行左连接,从 table1table2 中选择所有字段的记录,即使 table2 中没有匹配的记录,也会返回 table1 中的所有记录,未匹配到的部分会用 NULL 填充。

4.右连接

SELECT * FROM `table1` t1 RIGHT JOIN `table2` t2 ON t1.id = t2.id

这个查询进行右连接,从 table1table2 中选择所有字段的记录,即使 table1 中没有匹配的记录,也会返回 table2 中的所有记录,未匹配到的部分会用 NULL 填充。

假设我们有两个索引 table1table2,对应于 SQL 中的两个表。

创建索引 table1

PUT /`table1`
{
  "mappings": {
    "properties": {
      "id": { "type": "integer" },
      "name": { "type": "text" }
    }
  }
}

创建索引 table2

PUT /`table2`
{
  "mappings": {
    "properties": {
      "id": { "type": "integer" },
      "value": { "type": "text" }
    }
  }
}

导入数据到 table1

POST /`table1`/_bulk
{ "index": { "_id": 1 } }
{ "id": 1, "name": "Alice" }
{ "index": { "_id": 2 } }
{ "id": 2, "name": "Bob" }
{ "index": { "_id": 3 } }
{ "id": 3, "name": "Charlie" }
{ "index": { "_id": 4 } }
{ "id": 4, "name": "David" }

导入数据到 table2

POST /`table2`/_bulk
{ "index": { "_id": 1 } }
{ "id": 1, "value": "Value1" }
{ "index": { "_id": 2 } }
{ "id": 2, "value": "Value2" }
{ "index": { "_id": 5 } }
{ "id": 5, "value": "Value5" }
{ "index": { "_id": 6 } }
{ "id": 6, "value": "Value6" }

导入数据后,可以使用 SQL 来执行这些查询:

1.子查询:

POST /_sql
{
  "query": "SELECT * FROM `table1` WHERE id IN (SELECT id FROM `table2`)"
}

2.内连接:

POST /_sql
{
  "query": "SELECT * FROM `table1` t1 JOIN `table2` t2 ON t1.id = t2.id"
}

3.左连接:

POST /_sql
{
  "query": "SELECT * FROM `table1` t1 LEFT JOIN `table2` t2 ON t1.id = t2.id"
}

4.右连接:

POST /_sql
{
  "query": "SELECT * FROM `table1` t1 RIGHT JOIN `table2` t2 ON t1.id = t2.id"
}

效果如下:

SQL 全文检索

matchmatch_phrase 是 Easysearch 中用于全文搜索的查询类型,它们在处理文本匹配方面有不同的用途:

1.match 查询:

  • match 查询用于对文档进行全文搜索。
  • 它将搜索关键词进行分词,并对这些分词后的词项进行搜索。
  • 适用于查询单个或多个字段,可以进行布尔操作(如 “AND”, “OR”)。
  • 例如,搜索 “Easysearch is powerful” 会被分词为 "Easysearch ", “is”, “powerful” 三个词,然后对这三个词进行搜索,文档中包含这些词的都会被认为是匹配的。
{
  "query": {
    "match": {
      "content": "Easysearch  is powerful"
    }
  }
}

2.match_phrase 查询:

  • match_phrase 查询用于短语搜索。
  • 它要求搜索的短语必须在文档中出现且词的顺序相同,词之间的间隔也必须与查询中的短语相同。
  • 适用于需要精确匹配短语的场景。
  • 例如,搜索 “Easysearch is powerful” 时,只有包含这个确切短语的文档才会被认为是匹配的。
{
  "query": {
    "match_phrase": {
      "content": "Easysearch  is powerful"
    }
  }
}

总结来说,match 更灵活,用于一般的关键词搜索,而 match_phrase 则用于需要精确匹配短语的搜索。

SQL 全文检索示例

我们先造一些数据,然后使用 SQL 来进行全文检索。

批量导入数据:

POST /table3/_bulk
{ "index": { "_id": 1 } }
{ "id": 1, "test": "The quick brown fox jumps over the lazy dog" }
{ "index": { "_id": 2 } }
{ "id": 2, "test": "Foxes are wild animals" }
{ "index": { "_id": 3 } }
{ "id": 3, "test": "Jump high to catch the ball" }
{ "index": { "_id": 4 } }
{ "id": 4, "test": "Some animals can jump very high" }
{ "index": { "_id": 5 } }
{ "id": 5, "test": "The lazy dog sleeps all day" }
{ "index": { "_id": 6 } }
{ "id": 6, "test": "The foxes jump all day" }

执行全文检索的 SQL 查询:

SELECT * FROM table3;

SELECT * FROM table3 WHERE match(test, 'jump');

SELECT * FROM table3 WHERE match_phrase(test, 'foxes jump');

总结

随着数据量的不断增加,高效的数据搜索和分析变得尤为重要。Elasticsearch 以其强大的全文搜索能力和灵活的数据处理能力成为行业标准。Easysearch 作为 Elasticsearch 的优化版本,不仅继承了其强大的功能,还在性能和安全性上做了进一步的提升,为企业提供了一个高效、稳定且易于迁移的搜索引擎解决方案。通过深入了解这些技术和实践其应用,开发者和企业能够更好地利用这些工具来应对现代数据挑战,推动业务的持续发展和创新。

关于 Easysearch 有奖征文活动

黑神话悟空

无论你是 Easysearch 的老用户,还是第一次听说这个名字,只要你对 INFINI Labs 旗下的 Easysearch 产品感兴趣,或者是希望了解 Easysearch,都可以参加这次活动。

详情查看:Easysearch 征文活动

作者:韩旭,亚马逊云技术支持,亚马逊云科技技领云博主,目前专注于云计算开发和大数据领域。

原文:https://infinilabs.cn/blog/2024/mastering-easysearch-syntax/

继续阅读 »

什么是 Easysearch

Elasticsearch 是一个基于 Apache Lucene 的开源分布式搜索和分析引擎,它被广泛应用于全文搜索、结构化搜索和分析等多种场景中。作为 Elasticsearch 的国产化替代方案,Easysearch 不仅保持了与原生 Elasticsearch 的高度兼容性,还在功能、性能、稳定性和扩展性方面进行了全面提升。对于开发团队来说,从 Elasticsearch 切换到 Easysearch 不需要做任何业务代码的调整,确保了无缝衔接和平滑迁移。

Easysearch 是基于 Elasticsearch 7.10.2 开源版本二次开发,所以支持 Elasticsearch 原始的 Query DSL 语法,基本的 SQL 语法,并且兼容现有 Elasticsearch 的 SDK,使得应用无需修改代码即可进行迁移。其平滑的迁移特性,如基于网关的无缝跨版本迁移与升级,提供了随时安全回退的能力。

在之前的文章中,我们已经介绍了 Easysearch 的搭建可视化工具的使用,今天我们将探讨 Easysearch 集群的基本概念和常用的 API。

Easysearch 集群的核心概念

Easysearch 集群由以下几个核心概念构成:

  1. 节点(Node):集群中的单个服务器,负责存储数据并参与集群的索引和搜索功能。
  2. 集群(Cluster):由一个或多个节点组成,拥有唯一的集群名,协同完成数据索引和查询任务。
  3. 索引(Index):存储相关数据的容器,类似于关系数据库中的数据库,一个索引包含多个文档。
  4. 文档(Document):索引中的基本数据单位,相当于关系数据库中的行。
  5. 字段(Field):文档中的一个属性,相当于数据库中的列。
  6. 分片(Shard):为了提高性能和扩展性,索引可以被分割成多个分片,每个分片是索引的一个部分。
  7. 副本(Replica):分片的副本,用于提高数据的可靠性和在节点出现故障时的可用性。

通过多个 API,例如 _cluster/health_cluster/stats,用户可以轻松查看集群的健康状态和详细信息,这些信息对于维护和优化 Easysearch 集群至关重要。

无论是在性能的提升,还是在功能的兼容性方面,Easysearch 都为用户提供了一个强大的搜索引擎平台,让从 Elasticsearch 到 Easysearch 的迁移变得无缝且高效。掌握其核心概念和 API 的使用,将帮助开发者更好地利用这些工具来构建和优化他们的搜索解决方案。

查看集群信息

在 Easysearch 中,可以通过多个 API 来查看集群的各种信息,包括集群的健康状况、节点信息和索引状态。以下是一些常用的查看集群信息的 API 和示例:

查看集群健康状况

_cluster/health API 可以查看集群的健康状态,包括集群是否处于正常状态、节点数量、分片状态等。

GET /_cluster/health

示例响应:

{
  "cluster_name": "my_cluster",
  "status": "green",
  "timed_out": false,
  "number_of_nodes": 3,
  "number_of_data_nodes": 3,
  "active_primary_shards": 5,
  "active_shards": 10,
  "relocating_shards": 0,
  "initializing_shards": 0,
  "unassigned_shards": 0,
  "delayed_unassigned_shards": 0,
  "number_of_pending_tasks": 0,
  "number_of_in_flight_fetch": 0,
  "task_max_waiting_in_queue_millis": 0,
  "active_shards_percent_as_number": 100.0
}

查看集群状态

_cluster/stats API 可以查看集群的详细状态,包括索引、节点、分片等信息。

GET /_cluster/stats

示例响应:

{
  "cluster_name": "my_cluster",
  "status": "green",
  "indices": {
    "count": 10,
    "shards": {
      "total": 20,
      "primaries": 10,
      "replication": 1.0,
      "index": {
        "shards": {
          "min": 1,
          "max": 5,
          "avg": 2.0
        }
      }
    }
  },
  "nodes": {
    "count": {
      "total": 3,
      "data": 3,
      "coordinating_only": 0,
      "master": 1,
      "ingest": 2
    },
    "os": {
      "available_processors": 12,
      "allocated_processors": 12
    },
    "process": {
      "cpu": {
        "percent": 10
      },
      "open_file_descriptors": {
        "min": 100,
        "max": 300,
        "avg": 200
      }
    }
  }
}

查看节点信息

_nodes API 可以查看集群中节点的详细信息,包括节点角色、IP 地址、内存使用情况等。

GET /_nodes

示例响应:

{
  "cluster_name": "my_cluster",
  "nodes": {
    "node_id_1": {
      "name": "node_1",
      "transport_address": "192.168.1.1:9300",
      "host": "192.168.1.1",
      "ip": "192.168.1.1",
      "roles": ["master", "data", "ingest"],
      "os": {
        "available_processors": 4,
        "allocated_processors": 4
      },
      "process": {
        "cpu": {
          "percent": 10
        },
        "open_file_descriptors": 200
      }
    },
    "node_id_2": {
      "name": "node_2",
      "transport_address": "192.168.1.2:9300",
      "host": "192.168.1.2",
      "ip": "192.168.1.2",
      "roles": ["data"],
      "os": {
        "available_processors": 4,
        "allocated_processors": 4
      },
      "process": {
        "cpu": {
          "percent": 15
        },
        "open_file_descriptors": 150
      }
    }
  }
}

查看索引状态

_cat/indices API 可以查看集群中所有索引的状态,包括文档数、存储大小、分片数等信息。

GET /_cat/indices?v

示例响应:

health status index   uuid                   pri rep docs.count docs.deleted store.size pri.store.size
green  open   index_1 SxNUd84vRl6QH5P7g0T4Vg   1   1          0            0       230b           230b
green  open   index_2 NxEYib4yToCnA1PpQ8P4Xw   5   1        100            1      10mb           5mb

这些 API 可以帮助你全面了解 Easysearch 集群的状态和健康状况,从而更好地管理和维护集群。

增删改查操作

在 Easysearch 中,增删改查操作是管理数据和索引的基本功能。以下是如何使用这些操作的详细示例。

创建索引

创建一个新的索引,并指定分片和副本的数量:

PUT /my_index
{
  "settings": {
    "number_of_shards": 3,
    "number_of_replicas": 2
  }
}

删除索引

删除一个不再需要的索引:

DELETE /my_index

添加文档

通过 POST 或 PUT 请求向索引中添加文档:

POST /my_index/_doc/1
{
  "name": "John Doe",
  "age": 30,
  "occupation": "Engineer"
}
PUT /my_index/_doc/1
{
  "name": "John Doe",
  "age": 30,
  "occupation": "Engineer"
}

POSTPUT 方法用于不同的操作,尽管它们都可以用于添加或更新文档,但它们的行为有所不同。

POST /my_index/_doc/1 方法用于创建或替换一个文档。如果指定的文档 ID 已经存在,POST 请求将更新整个文档(不会合并字段)。如果文档 ID 不存在,它将创建一个新的文档。


POST /my_index/_doc/1
{
  "name": "John Doe",
  "age": 30,
  "occupation": "Engineer"
}

PUT /my_index/_doc/1 方法通常用于创建一个新的文档,或者完全替换一个已存在的文档。与 POST 类似,如果指定的文档 ID 已经存在,PUT 请求将替换整个文档。

PUT /my_index/_doc/1
{
  "name": "John Doe",
  "age": 30,
  "occupation": "Engineer"
}

1.使用场景:

  • POST:更适合用于添加或部分更新文档,即使文档 ID 已经存在。
  • PUT:更适合用于创建或完全替换文档。

2.ID 自动生成:

  • POST 请求可以不提供文档 ID,此时 Easysearch 会自动生成一个文档 ID。
  • PUT 请求必须提供文档 ID,如果未提供,则会返回错误。

3.部分更新:

  • POST 请求可以用于部分更新(通过 _update API)。
  • PUT 请求用于完全替换文档,不支持部分更新。

如果文档 ID 已经存在,POSTPUT 都会覆盖整个文档,并且效果是一样的。但是,通常 POST 用于提交数据,而 PUT 用于上传和替换资源。

1.使用 POST 方法添加或更新文档:

POST /my_index/_doc/1
{
  "name": "John Doe",
  "age": 30,
  "occupation": "Engineer"
}

2.使用 PUT 方法添加或更新文档:

PUT /my_index/_doc/1
{
  "name": "John Doe",
  "age": 30,
  "occupation": "Engineer"
}

在这两个示例中,结果都是在索引 my_index 中创建或更新文档 ID 为 1 的文档。无论使用 POST 还是 PUT,如果文档 ID 已存在,都会覆盖原有的文档内容。

新建文档

使用 _create 方法新建文档,如果文档已经存在则返回错误:

PUT /my_index/_create/1
{
  "a": 1
}

如果尝试新建已存在的文档,将会出现如下错误:

{
  "error": {
    "root_cause": [
      {
        "type": "version_conflict_engine_exception",
        "reason": "[1]: version conflict, document already exists (current version [1])",
        "index_uuid": "1xWdHLTaTm6l6HbqACaIEA",
        "shard": "0",
        "index": "my_index"
      }
    ],
    "type": "version_conflict_engine_exception",
    "reason": "[1]: version conflict, document already exists (current version [1])",
    "index_uuid": "1xWdHLTaTm6l6HbqACaIEA",
    "shard": "0",
    "index": "my_index"
  },
  "status": 409
}

获取文档

通过 ID 获取文档的详细信息:

GET /my_index/_doc/1

更新文档

更新文档的特定字段,保留原有字段:

POST /my_index/_update/1
{
  "doc": {
    "age": 31
  }
}

删除文档

通过 ID 删除指定的文档:

DELETE /my_index/_doc/1

查询所有文档

查询索引中的所有文档:

GET /my_index/_search
{
  "query": {
    "match_all": {}
  }
}

这个是 《老杨玩搜索》中总结的图,可以作为“小抄”来记忆:

批量操作 (_bulk API)

_bulk API 用于在一次请求中执行多个索引、删除和更新操作,这对于批量处理大规模数据非常有用,可以显著提高性能和效率。以下是 _bulk API 的基本使用示例:

POST /my_index/_bulk
{ "index": { "_id": "1" } }
{ "name": "John Doe", "age": 30, "occupation": "Engineer" }
{ "index": { "_id": "2" } }
{ "name": "Jane Doe", "age": 25, "occupation": "Designer" }
{ "update": { "_id": "1" } }
{ "doc": { "age": 31 } }

_bulk API 的请求体由多个操作和文档组成。每个操作行包含一个动作描述行和一个可选的源文档行。动作描述行指明了操作的类型(例如,index、create、delete、update)以及操作的元数据。源文档行则包含了实际的数据。

每个操作之间需要用换行符分隔,并且请求体最后必须以换行符结尾。

POST /_bulk
{ "index": { "_index": "a", "_id": "1" } }
{ "name": "John Doe", "age": 30, "occupation": "Engineer" }
{ "index": { "_index": "b", "_id": "2" } }
{ "name": "Jane Doe", "age": 25, "occupation": "Designer" }
{ "update": { "_index": "a", "_id": "1" } }
{ "doc": { "age": 31 } }

分词器

在 Easysearch 中,分词器(Analyzer)用于将文本分解为词项(terms),是全文搜索和文本分析的基础。分词器通常由字符过滤器(Character Filters)、分词器(Tokenizer)和词项过滤器(Token Filters)组成。以下是关于分词器的详细介绍:

1.字符过滤器(Character Filters):在分词之前对文本进行预处理。例如,去除 HTML 标签,替换字符等。

2.分词器(Tokenizer):将文本分解为词项(tokens)。这是分词过程的核心。

3.词项过滤器(Token Filters):对词项进行处理,如小写化、去除停用词、词干提取等。

只有 text 字段支持全文检索,返回的结果根据相似度打分,我们一起看下

POST /index/_mapping
{
  "properties": {
    "content": {
      "type": "text",
      "analyzer": "ik_max_word",
      "search_analyzer": "ik_smart"
    }
  }
}

.POST /index/_mapping

  • 这个部分表示要向名为 index 的索引添加或更新映射设置。

2.“properties”

  • properties 定义了索引中文档的字段结构。在这个例子中,定义了一个名为 content 的字段。

3.“content”

  • 定义了名为 content 的字段。

4.“type”: “text”

type 字段指定 content 字段的数据类型为 texttext 类型适用于需要分词和全文搜索的字段。

5.“analyzer”: “ik_max_word”

analyzer 字段指定索引时使用的分词器为ik_max_wordik_max_word 是 IK 分词器中的一种,它会尽可能多地将文本分解为更多的词项。

6.“search_analyzer”: “ik_smart”

search_analyzer 字段指定搜索时使用的分词器为ik_smartik_smart 是 IK 分词器中的另一种,它会更智能地进行分词,以提高搜索的准确性。

当然,在设置这个 mapping 的时候可以使用同样的分词器,也可以使用不同的分词器。这里介绍下 IK 分词器:

  • IK 分词器是一种中文分词器,适用于中文文本的分词。IK 分词器有两种分词模式:ik_max_wordik_smart
    • ik_max_word:将文本尽可能多地切分成词项,适用于需要更高召回率的场景。
    • ik_smart:进行最智能的分词,适用于需要更高精度的搜索场景。

这个 DSL 的设置意味着,在向这个索引添加或更新文档时,content 字段的文本会使用ik_max_word 分词器进行分词处理,以确保文本被尽可能多地切分成词项。而在搜索时,content 字段的文本会使用ik_smart 分词器进行分词处理,以提高搜索的准确性和相关性。

以下是关于 standard,ik_smart,ik_max_word 这几个分词器的对比:

GET /_analyze
{
  "tokenizer": "standard",
  "text": "我,机器人"
}

GET /_analyze
{
  "tokenizer": "ik_smart",
  "text": "我,机器人"
}

GET /_analyze
{
  "tokenizer": "ik_max_word",
  "text": "我,机器人"
}

结果如下:

# GET /_analyze (standard)
{
  "tokens": [
    {
      "token": "我",
      "start_offset": 0,
      "end_offset": 1,
      "type": "<IDEOGRAPHIC>",
      "position": 0
    },
    {
      "token": "机",
      "start_offset": 2,
      "end_offset": 3,
      "type": "<IDEOGRAPHIC>",
      "position": 1
    },
    {
      "token": "器",
      "start_offset": 3,
      "end_offset": 4,
      "type": "<IDEOGRAPHIC>",
      "position": 2
    },
    {
      "token": "人",
      "start_offset": 4,
      "end_offset": 5,
      "type": "<IDEOGRAPHIC>",
      "position": 3
    }
  ]
}
# GET /_analyze(ik_smart)
{
  "tokens": [
    {
      "token": "我",
      "start_offset": 0,
      "end_offset": 1,
      "type": "CN_CHAR",
      "position": 0
    },
    {
      "token": "机器人",
      "start_offset": 2,
      "end_offset": 5,
      "type": "CN_WORD",
      "position": 1
    }
  ]
}
# GET /_analyze (ik_max_word)
{
  "tokens": [
    {
      "token": "我",
      "start_offset": 0,
      "end_offset": 1,
      "type": "CN_CHAR",
      "position": 0
    },
    {
      "token": "机器人",
      "start_offset": 2,
      "end_offset": 5,
      "type": "CN_WORD",
      "position": 1
    },
    {
      "token": "机器",
      "start_offset": 2,
      "end_offset": 4,
      "type": "CN_WORD",
      "position": 2
    },
    {
      "token": "人",
      "start_offset": 4,
      "end_offset": 5,
      "type": "CN_CHAR",
      "position": 3
    }
  ]
}

如果使用了不存在的分词器会出现这个错误。

{
  "error": {
    "root_cause": [
      {
        "type": "illegal_argument_exception",
        "reason": "failed to find global tokenizer under [simple]"
      }
    ],
    "type": "illegal_argument_exception",
    "reason": "failed to find global tokenizer under [simple]"
  },
  "status": 400
}

精确搜索/正则表达式搜索/通配符

在 Easysearch 中,精确搜索、正则表达式搜索和通配符搜索是三种不同的搜索方式,各有其应用场景和特点:

1.精确搜索 (Term Query)

  • 精确搜索用于查找与搜索词完全匹配的文档。
  • 不进行分词处理,通常用于关键字、ID、标签等字段的精确匹配。
  • 适用于结构化数据或不需要分词的字段(如数字、日期、布尔值等)。
{
  "query": {
    "term": {
      "status": "active"
    }
  }
}

2.正则表达式搜索 (Regexp Query)

  • 正则表达式搜索用于基于正则表达式模式匹配的文档搜索。
  • 支持复杂的字符串匹配模式,但性能可能较低,特别是当数据量较大时。
  • 适用于需要灵活且复杂匹配条件的搜索。
{
  "query": {
    "regexp": {
      "content": "Easysearch .*powerful"
    }
  }
}

3.通配符搜索 (Wildcard Query)

  • 通配符搜索用于通过通配符模式匹配文档。
  • 支持 ?(匹配单个字符)和 *(匹配零个或多个字符)。
  • 性能相对较差,因为通配符搜索可能需要扫描大量数据。
{
  "query": {
    "wildcard": {
      "username": "john*"
    }
  }
}
  • 精确搜索:用于需要绝对匹配特定词语或不需要分词的字段。例如,查找特定用户 ID 或状态。
  • 正则表达式搜索:用于需要复杂字符串模式匹配的场景,但要谨慎使用,避免性能问题。
  • 通配符搜索:用于简单模式匹配,但同样需要注意性能影响,尽量避免在大数据集上频繁使用。

接下来看这个例子,我们将使用批量导入数据,然后进行几种不同类型的查询,包括精确查询、通配符查询和正则表达式查询。

POST /users/_bulk
{ "index": { "_index": "users", "_id": 1 }}
{ "username": "john_doe", "status": "active", "email": "john.doe@example.com", "bio": "John loves Easysearch  and open-source technologies." }
{ "index": { "_index": "users", "_id": 2 }}
{ "username": "jane_doe", "status": "inactive", "email": "jane.doe@example.com", "bio": "Jane is a data scientist working with big data." }
{ "index": { "_index": "users", "_id": 3 }}
{ "username": "john_smith", "status": "active", "email": "john.smith@example.com", "bio": "John enjoys hiking and nature." }
{ "index": { "_index": "users", "_id": 4 }}
{ "username": "alice_jones", "status": "active", "email": "alice.jones@example.com", "bio": "Alice is a software engineer specialized in JavaScript." }
{ "index": { "_index": "users", "_id": 5 }}
{ "username": "bob_jones", "status": "inactive", "email": "bob.jones@example.com", "bio": "Bob is an AI enthusiast and machine learning expert." }

1.精确查询:查询状态为 “active” 的用户。

GET /users/_search
{
  "query": {
    "term": {
      "status": "active"
    }
  }
}

2.通配符查询:查询 bio 字段中包含 “John” 开头的词。

GET /users/_search
{
  "query": {
    "wildcard": {
      "bio": "John*"
    }
  }
}

3.正则表达式查询:查询用户名以 “john” 开头的用户

GET /users/_search
{
  "query": {
    "regexp": {
      "username": "john.*"
    }
  }
}

通过这些例子,你可以看到如何在 Easysearch 中使用批量导入数据,然后使用各种查询方法来检索特定条件的数据。这些查询方法可以帮助你高效地搜索和分析数据,以满足不同的业务需求。

这里同样是《老杨玩搜索》中总结的“小抄”来方便记忆:

多字段查询

在 Easysearch 中,多字段查询允许您在多个字段上同时执行搜索,以获取更精确的结果。最常用的多字段查询类型是 multi_match 查询。multi_match 查询是 match 查询的扩展,能够在多个字段中搜索指定的关键词。

multi_match 查询支持多种匹配模式,如 best_fieldsmost_fieldscross_fieldsphrasephrase_prefix。以下是各模式的简要介绍:

  • best_fields:默认模式,选择匹配度最高的字段。
  • most_fields:计算每个字段的匹配度,然后将匹配度相加。
  • cross_fields:将多个字段视为一个字段进行匹配,适用于分析文本被分散到多个字段的情况。
  • phrase:短语匹配,确保词项顺序与查询相同。
  • phrase_prefix:短语前缀匹配,允许词项的部分匹配。

我们先导入一些示例数据到一个索引 documents 中:

POST /documents/_bulk
{ "index": { "_id": 1 } }
{ "title": "Easysearch  Guide", "content": "This is an introductory guide to Easysearch ." }
{ "index": { "_id": 2 } }
{ "title": "Advanced Easysearch ", "content": "This guide covers advanced topics in Easysearch ." }
{ "index": { "_id": 3 } }
{ "title": "Easysearch  in Action", "content": "Practical guide to Easysearch  usage." }
{ "index": { "_id": 4 } }
{ "title": "Learning Easysearch ", "content": "Beginner's guide to learning Easysearch ." }

我们将使用 multi_match 查询在 titlecontent 字段中同时搜索关键词。

1.基本 multi_match 查询

POST /documents/_search
{
  "query": {
    "multi_match": {
      "query": "guide",
      "fields": ["title", "content"]
    }
  }
}

2.指定匹配模式为 best_fields

POST /documents/_search
{
  "query": {
    "multi_match": {
      "query": "guide",
      "fields": ["title", "content"],
      "type": "best_fields"
    }
  }
}

3.指定匹配模式为 most_fields

POST /documents/_search
{
  "query": {
    "multi_match": {
      "query": "guide",
      "fields": ["title", "content"],
      "type": "most_fields"
    }
  }
}

4.使用 cross_fields 模式

POST /documents/_search
{
  "query": {
    "multi_match": {
      "query": "Easysearch  guide",
      "fields": ["title", "content"],
      "type": "cross_fields"
    }
  }
}

5.短语匹配 (phrase)

POST /documents/_search
{
  "query": {
    "multi_match": {
      "query": "introductory guide",
      "fields": ["title", "content"],
      "type": "phrase"
    }
  }
}

6.短语前缀匹配 (phrase_prefix)

POST /documents/_search
{
  "query": {
    "multi_match": {
      "query": "introductory gui",
      "fields": ["title", "content"],
      "type": "phrase_prefix"
    }
  }
}
  • query:要搜索的关键词或短语。
  • fields:要搜索的字段列表,可以包含一个或多个字段。
  • type:指定匹配模式,默认为 best_fields。

使用 multi_match 查询,您可以在多个字段上同时执行搜索,获得更精确和全面的结果。通过指定不同的匹配模式,您可以调整查询行为以满足特定的搜索需求。无论是基本关键词匹配、短语匹配还是跨字段匹配,multi_match 查询都提供了强大的功能来处理复杂的搜索场景。

除此之外,还可以使用 boost 参数用于调整特定字段的权重,从而影响搜索结果的相关性评分。multi_match 查询支持为不同字段设置不同的 boost 值,以便在搜索结果中优先显示某些字段的匹配项。

布尔查询

布尔查询是 Easysearch 中非常强大且灵活的一种查询方式,它允许用户通过组合多个查询条件来实现复杂的搜索需求。布尔查询使用 bool 查询类型,可以包含以下几种子句:mustfiltermust_notshould。每种子句都有其特定的用途和语义。

1.must

  • 包含在 must 数组中的查询条件必须匹配,类似于逻辑上的 AND 操作。
  • 如果有多个条件,所有条件都必须满足,文档才会被包含在结果集中。

2.filter

  • 包含在 filter 数组中的查询条件必须匹配,但它不会影响评分。
  • filter 子句通常用于对性能要求较高的过滤操作,因为它不计算相关性评分。

3.must_not

  • 包含在 must_not 数组中的查询条件必须不匹配,类似于逻辑上的 NOT 操作。
  • 如果有任何一个条件匹配,文档就会被排除在结果集之外。

4.should

  • 包含在 should 数组中的查询条件至少匹配一个。
  • 如果布尔查询中没有 must 子句,则至少要匹配一个 should 子句。
  • should 子句在计算相关性评分时也有影响。

5.minimum_should_match

  • 指定 should 子句中至少需要满足的条件数量。

首先,我们需要创建一个名为 books 的索引,并定义它的映射(mappings)。映射用于指定每个字段的数据类型。在这个例子中,类别书名字段都被定义为 keyword 类型,这是因为我们需要进行精确匹配查询。

PUT /books
{
  "mappings": {
    "properties": {
      "类别": { "type": "keyword" },
      "书名": { "type": "keyword" }
    }
  }
}

接下来,我们使用批量操作(bulk API)将一些示例数据导入到 books 索引中。这些数据包括不同类别的书籍。

POST /books/_bulk
{ "index": { "_id": 1 } }
{ "类别": "文学", "书名": "我的阿勒泰" }
{ "index": { "_id": 2 } }
{ "类别": "文学", "书名": "平凡的世界" }
{ "index": { "_id": 3 } }
{ "类别": "科学", "书名": "时间简史" }
{ "index": { "_id": 4 } }
{ "类别": "文学", "书名": "百年孤独" }
{ "index": { "_id": 5 } }
{ "类别": "文学", "书名": "红楼梦" }

现在,我们使用布尔查询来搜索类别为“文学”并且书名为“我的阿勒泰”的文档。这里使用的是 must子句,表示查询结果必须满足所有条件。

POST /books/_search
{
  "query": {
    "bool": {
      "must": [
        { "term": { "类别": "文学" } },
        { "term": { "书名": "我的阿勒泰" } }
      ]
    }
  }
}

我们还可以使用 filter 子句来执行相同的查询。filter 子句用于过滤文档,且不会影响文档的相关性评分。这在不需要计算相关性评分时可以提高查询性能。

POST /books/_search
{
  "query": {
    "bool": {
      "filter": [
        { "term": { "类别": "文学" } },
        { "term": { "书名": "我的阿勒泰" } }
      ]
    }
  }
}

当我们执行上述查询时,期望返回的结果是 books 索引中类别为“文学”且书名为“我的阿勒泰”的文档。无论是使用 must 还是 filter 子句,结果应该都是:

{
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "hits": [
      {
        "_index": "books",
        "_id": "1",
        "_source": {
          "类别": "文学",
          "书名": "我的阿勒泰"
        }
      }
    ]
  }
}

POST /_search
{
  "query": {
    "bool": {
      "must": [
        { "term": { "user.id": "kimchy" } }
      ],
      "filter": [
        { "term": { "tags": "production" } }
      ],
      "must_not": [
        {
          "range": {
            "age": { "gte": 10, "lte": 20 }
          }
        }
      ],
      "should": [
        { "term": { "tags": "env1" } },
        { "term": { "tags": "deployed" } }
      ],
      "minimum_should_match": 1,
      "boost": 1.0
    }
  }
}
  • must 子句:必须匹配的条件,文档必须包含 user.idkimchy
  • filter 子句:过滤条件,文档必须包含 tagsproduction ,但不会影响评分。
  • must_not子句:不匹配的条件,文档的 age 字段不能在 10 到 20 之间。
  • should 子句:可选匹配条件,至少需要匹配一个 should 子句中的条件。这里要求 tags 字段匹配 env1deployed
  • minimum_should_match:至少需要匹配一个 should 子句中的条件。
  • boost:提升查询的整体评分。

为了展示这个 DSL ,我们需要创建一个索引并导入一些数据。假设我们要在 Easysearch 中创建一个索引 users ,并插入一些测试数据。

创建索引

PUT /users
{
  "mappings": {
    "properties": {
      "user.id": { "type": "keyword" },
      "tags": { "type": "keyword" },
      "age": { "type": "integer" }
    }
  }
}

批量导入数据

POST /users/_bulk
{ "index": { "_id": 1 } }
{ "user.id": "kimchy", "tags": ["production", "env1"], "age": 25 }
{ "index": { "_id": 2 } }
{ "user.id": "kimchy", "tags": ["production"], "age": 15 }
{ "index": { "_id": 3 } }
{ "user.id": "kimchy", "tags": ["deployed"], "age": 30 }
{ "index": { "_id": 4 } }
{ "user.id": "kimchy", "tags": ["test"], "age": 35 }
{ "index": { "_id": 5 } }
{ "user.id": "other", "tags": ["production"], "age": 25 }

接下来执行布尔查询:

POST /users/_search
{
  "query": {
    "bool": {
      "must": [
        { "term": { "user.id": "kimchy" } }
      ],
      "filter": [
        { "term": { "tags": "production" } }
      ],
      "must_not": [
        {
          "range": {
            "age": { "gte": 10, "lte": 20 }
          }
        }
      ],
      "should": [
        { "term": { "tags": "env1" } },
        { "term": { "tags": "deployed" } }
      ],
      "minimum_should_match": 1,
      "boost": 1.0
    }
  }
}

根据以上查询,预期返回的结果应该符合以下条件:

  1. user.id必须是 kimchy(由 must 子句决定)。
  2. tags 必须包含 production (由 filter 子句决定)。
  3. age 字段不在 10 到 20 之间(由 must_not 子句决定)。
  4. tags字段中至少包含 env1deployed 中的一个(由 should 子句和 minimum_should_match 参数决定)。
{
  "took": 1,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 1.3769134,
    "hits": [
      {
        "_index": "users",
        "_type": "_doc",
        "_id": "1",
        "_score": 1.3769134,
        "_source": {
          "user.id": "kimchy",
          "tags": ["production", "env1"],
          "age": 25
        }
      }
    ]
  }
}

SQL 搜索

Easysearch 直接支持 SQL 查询,无需额外安装插件,同时兼容 Elasticsearch 的 SQL 调用方式,还可以直接编写原生 SQL 查询。

以下是一些测试 SQL 语句的示例:

SELECT * FROM my_index;

SELECT * FROM my_index LIMIT 2;

SELECT * FROM my_index ORDER BY name;

SELECT name AS full_name, age FROM my_index WHERE age > 25;

SELECT name AS full_name, age FROM my_index WHERE age = 25;

SELECT * FROM my_index WHERE age IS NULL;

SELECT DISTINCT age FROM my_index;

SELECT MIN(age), MAX(age), AVG(age) FROM my_index;

SELECT age, COUNT(*) AS CNT FROM my_index GROUP BY age;

使用 Easysearch 执行 SQL 查询

Easysearch 提供了对直接使用 SQL 查询的支持。以下是如何在 Easysearch 中通过 POST 请求使用 _sql 端点进行查询的示例:

执行 SQL 查询非常简单,只需通过 POST 请求发送 SQL 查询即可。以下是一个示例:

POST /_sql
{
  "query": "SELECT name AS full_name, age FROM my_index WHERE age > 25"
}

你也可以规定返回 JSON 格式:

POST /_sql?format=json
{
  "query": "SELECT name AS full_name, age FROM my_index WHERE age > 25"
}

和 Elasticsearch 一样,Easysearch 允许你通过 POST 请求直接在集群上运行 SQL 查询,并返回查询结果。以下是一些常见的 SQL 查询示例及其对应的 POST 请求:

1.查询所有文档

POST /_sql
{
  "query": "SELECT * FROM my_index"
}

2.限制返回文档数

POST /_sql
{
  "query": "SELECT * FROM my_index LIMIT 2"
}

3.按字段排序

POST /_sql
{
  "query": "SELECT * FROM my_index ORDER BY name"
}

4.筛选条件查询

POST /_sql
{
  "query": "SELECT name AS full_name, age FROM my_index WHERE age > 25"
}

5.精确值查询

POST /_sql
{
  "query": "SELECT name AS full_name, age FROM my_index WHERE age = 25"
}

6.查询空值

POST /_sql
{
  "query": "SELECT * FROM my_index WHERE age IS NULL"
}

7.查询唯一值

POST /_sql
{
  "query": "SELECT DISTINCT age FROM my_index"
}

8.聚合函数查询

POST /_sql
{
  "query": "SELECT MIN(age), MAX(age), AVG(age) FROM my_index"
}

9.分组统计

POST /_sql
{
  "query": "SELECT age, COUNT(*) AS CNT FROM my_index GROUP BY age"
}

多表操作的 SQL 语句

以下是多表操作的 SQL 语句及其解释:

1.子查询

SELECT * FROM `table1` t1 WHERE t1.id IN (SELECT id FROM `table2`)

这个查询从 table1 中选择所有字段的记录,其中这些记录的 idtable2 表中也存在。

2.内连接

SELECT * FROM `table1` t1 JOIN `table2` t2 ON t1.id = t2.id

这个查询进行内连接,从 table1table2 中选择所有字段的记录,前提是 table1table2id 相等。

3.左连接

SELECT * FROM `table1` t1 LEFT JOIN `table2` t2 ON t1.id = t2.id

这个查询进行左连接,从 table1table2 中选择所有字段的记录,即使 table2 中没有匹配的记录,也会返回 table1 中的所有记录,未匹配到的部分会用 NULL 填充。

4.右连接

SELECT * FROM `table1` t1 RIGHT JOIN `table2` t2 ON t1.id = t2.id

这个查询进行右连接,从 table1table2 中选择所有字段的记录,即使 table1 中没有匹配的记录,也会返回 table2 中的所有记录,未匹配到的部分会用 NULL 填充。

假设我们有两个索引 table1table2,对应于 SQL 中的两个表。

创建索引 table1

PUT /`table1`
{
  "mappings": {
    "properties": {
      "id": { "type": "integer" },
      "name": { "type": "text" }
    }
  }
}

创建索引 table2

PUT /`table2`
{
  "mappings": {
    "properties": {
      "id": { "type": "integer" },
      "value": { "type": "text" }
    }
  }
}

导入数据到 table1

POST /`table1`/_bulk
{ "index": { "_id": 1 } }
{ "id": 1, "name": "Alice" }
{ "index": { "_id": 2 } }
{ "id": 2, "name": "Bob" }
{ "index": { "_id": 3 } }
{ "id": 3, "name": "Charlie" }
{ "index": { "_id": 4 } }
{ "id": 4, "name": "David" }

导入数据到 table2

POST /`table2`/_bulk
{ "index": { "_id": 1 } }
{ "id": 1, "value": "Value1" }
{ "index": { "_id": 2 } }
{ "id": 2, "value": "Value2" }
{ "index": { "_id": 5 } }
{ "id": 5, "value": "Value5" }
{ "index": { "_id": 6 } }
{ "id": 6, "value": "Value6" }

导入数据后,可以使用 SQL 来执行这些查询:

1.子查询:

POST /_sql
{
  "query": "SELECT * FROM `table1` WHERE id IN (SELECT id FROM `table2`)"
}

2.内连接:

POST /_sql
{
  "query": "SELECT * FROM `table1` t1 JOIN `table2` t2 ON t1.id = t2.id"
}

3.左连接:

POST /_sql
{
  "query": "SELECT * FROM `table1` t1 LEFT JOIN `table2` t2 ON t1.id = t2.id"
}

4.右连接:

POST /_sql
{
  "query": "SELECT * FROM `table1` t1 RIGHT JOIN `table2` t2 ON t1.id = t2.id"
}

效果如下:

SQL 全文检索

matchmatch_phrase 是 Easysearch 中用于全文搜索的查询类型,它们在处理文本匹配方面有不同的用途:

1.match 查询:

  • match 查询用于对文档进行全文搜索。
  • 它将搜索关键词进行分词,并对这些分词后的词项进行搜索。
  • 适用于查询单个或多个字段,可以进行布尔操作(如 “AND”, “OR”)。
  • 例如,搜索 “Easysearch is powerful” 会被分词为 "Easysearch ", “is”, “powerful” 三个词,然后对这三个词进行搜索,文档中包含这些词的都会被认为是匹配的。
{
  "query": {
    "match": {
      "content": "Easysearch  is powerful"
    }
  }
}

2.match_phrase 查询:

  • match_phrase 查询用于短语搜索。
  • 它要求搜索的短语必须在文档中出现且词的顺序相同,词之间的间隔也必须与查询中的短语相同。
  • 适用于需要精确匹配短语的场景。
  • 例如,搜索 “Easysearch is powerful” 时,只有包含这个确切短语的文档才会被认为是匹配的。
{
  "query": {
    "match_phrase": {
      "content": "Easysearch  is powerful"
    }
  }
}

总结来说,match 更灵活,用于一般的关键词搜索,而 match_phrase 则用于需要精确匹配短语的搜索。

SQL 全文检索示例

我们先造一些数据,然后使用 SQL 来进行全文检索。

批量导入数据:

POST /table3/_bulk
{ "index": { "_id": 1 } }
{ "id": 1, "test": "The quick brown fox jumps over the lazy dog" }
{ "index": { "_id": 2 } }
{ "id": 2, "test": "Foxes are wild animals" }
{ "index": { "_id": 3 } }
{ "id": 3, "test": "Jump high to catch the ball" }
{ "index": { "_id": 4 } }
{ "id": 4, "test": "Some animals can jump very high" }
{ "index": { "_id": 5 } }
{ "id": 5, "test": "The lazy dog sleeps all day" }
{ "index": { "_id": 6 } }
{ "id": 6, "test": "The foxes jump all day" }

执行全文检索的 SQL 查询:

SELECT * FROM table3;

SELECT * FROM table3 WHERE match(test, 'jump');

SELECT * FROM table3 WHERE match_phrase(test, 'foxes jump');

总结

随着数据量的不断增加,高效的数据搜索和分析变得尤为重要。Elasticsearch 以其强大的全文搜索能力和灵活的数据处理能力成为行业标准。Easysearch 作为 Elasticsearch 的优化版本,不仅继承了其强大的功能,还在性能和安全性上做了进一步的提升,为企业提供了一个高效、稳定且易于迁移的搜索引擎解决方案。通过深入了解这些技术和实践其应用,开发者和企业能够更好地利用这些工具来应对现代数据挑战,推动业务的持续发展和创新。

关于 Easysearch 有奖征文活动

黑神话悟空

无论你是 Easysearch 的老用户,还是第一次听说这个名字,只要你对 INFINI Labs 旗下的 Easysearch 产品感兴趣,或者是希望了解 Easysearch,都可以参加这次活动。

详情查看:Easysearch 征文活动

作者:韩旭,亚马逊云技术支持,亚马逊云科技技领云博主,目前专注于云计算开发和大数据领域。

原文:https://infinilabs.cn/blog/2024/mastering-easysearch-syntax/

收起阅读 »