对于刚开始接触 INFINI Easysearch 的开发者来说,最先打交道的往往是数据的写入,但最核心的价值则体现在搜索上。与传统关系型数据库使用 SQL 不同,Easysearch 使用基于 JSON 的 Query DSL(Domain Specific Language,领域特定语言)来定义查询。
本文将带你入门 Easysearch 的搜索机制,从最基础的 match_all 开始,深入理解 DSL 结构及查询结果的含义。
1. 认识 _search API #
在 Easysearch 中,搜索是通过发送 RESTful 请求到 _search 端点来实现的。它既支持 URL 参数查询(URI Search),也支持功能更强大的请求体查询(Request Body Search)。在生产环境中,我们绝大多数情况都使用后者。
基本语法结构:
GET /<索引名>/_search
{
"query": { <查询条件> },
"from": <偏移量>,
"size": <返回条数>,
"sort": [ <排序规则> ],
"_source": [ <指定返回字段> ]
}
2. Hello World:使用 match_all 查询 #
最简单的查询莫过于 match_all。顾名思义,它匹配索引中的所有文档。这通常用于检查索引是否包含数据,或者作为聚合分析的背景集。
请求示例:
GET /products/_search
{
"query": {
"match_all": {}
}
}
注意:虽然它匹配了所有文档,但 Easysearch 默认只会返回前 10 条结果(类似于 SQL 的 LIMIT 10),这是为了防止网络传输过载。
3. 读懂搜索响应(Response Analysis) #
很多初学者看到 Easysearch 返回的层层嵌套的 JSON 会感到困惑。理解每个字段的含义是开发调试的基础。
假设上述 match_all 查询返回如下结果:
{
"took": 5,
"timed_out": false,
"_shards": {
"total": 3,
"successful": 3,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1000,
"relation": "eq"
},
"max_score": 1.0,
"hits": [
{
"_index": "products",
"_id": "1001",
"_score": 1.0,
"_source": {
"name": "Easysearch 权威指南",
"price": 99.0,
"category": "Book"
}
}
// ... 更多文档
]
}
}
字段深度解析:
- 元数据部分:
took: 搜索请求耗时的毫秒数。这是性能调优的关键指标。timed_out: 查询是否超时。_shards: 描述了分片参与情况。total是总分片数,failed大于 0 意味着部分数据可能不可用(例如某节点宕机)。
- 核心结果部分 (
hits** 对象)**:
hits.total.value: 最重要的数据。表示符合查询条件的文档总数(示例中为 1000 条)。hits.max_score: 本次搜索结果中最高的匹配评分。hits.hits: 具体的文档数组(默认返回前 10 个)。
- 文档详情部分 (
hits.hits** 数组)**:
_index: 文档所属索引。_id: 文档的唯一主键。_score: 相关性评分。Easysearch 默认按此字段降序排列。对于match_all,所有文档评分都是 1.0。_source: 原始数据。即你在写入时发送给 Easysearch 的完整 JSON 内容。
4. 控制查询结果:分页与字段过滤 #
在实际业务中,我们很少直接使用裸的 match_all,通常需要配合分页和字段选择。
4.1 分页 (Pagination) #
Easysearch 使用 from(跳过多少条)和 size(返回多少条)来实现分页。
GET /products/_search
{
"query": { "match_all": {} },
"from": 20, // 跳过前 20 条,即从第 21 条开始
"size": 10 // 返回 10 条
}
4.2 字段过滤 (Source Filtering) #
如果文档很大,但前端列表页只需要显示标题和价格,通过 _source 过滤可以显著减少网络传输流量,提升性能。
GET /products/_search
{
"query": { "match_all": {} },
"_source": ["name", "price"] // 结果中只返回这两个字段
}
5. 深度:Easysearch 的分布式查询流程 #
理解查询结果后,了解底层流程有助于理解性能特性。Easysearch 是分布式的,数据分散在不同分片(Shard)上。一次搜索请求实际上经历了 Query Then Fetch(先查询后取回) 两个阶段:
- Query 阶段:
- 协调节点(接收请求的节点)将查询请求转发给索引的所有分片(主分片或副本分片)。
- 每个分片在本地执行查询,计算文档评分,并生成一个优先队列(仅包含文档 ID 和 Score,不包含具体数据)。
- 各分片将优先队列返回给协调节点。
- Fetch 阶段:
- 协调节点对收集到的所有结果进行全局排序,确定最终需要返回的文档 ID。
- 协调节点向持有这些文档的具体分片发送
GET请求,抓取_source数据。 - 拼装最终 JSON,返回给客户端。
这就是为什么深度分页(例如 from: 10000, size: 10)会很慢的原因——协调节点需要处理 10010 条数据的排序,却只扔掉前 10000 条。
总结 #
_searchAPI 是与 Easysearch 交互的核心入口。- DSL 采用 JSON 结构,
match_all是最基础的查询类型。 - 学会解读
hits.total和_source是开发的第一步。 - 利用
from、size和_source过滤,可以让查询更加高效。
掌握了这些基础后,下一篇我们将深入探讨 Easysearch 强大的**全文检索(Full Text Search)与精确查询(Term Level Query)**的区别与应用。





