结构化搜索 #
结构化搜索针对的是“精确可判定”的字段:ID、枚举、时间、数值、状态位等。本页重点讲如何用好 term/terms/range/exists 这几类基础查询,并配合 filter 上下文使用。
适用字段与“不适用”的情况 #
适合用结构化查询的典型字段:
- 关键词/编码:订单号、用户 ID、设备 ID、状态码
- 数值:价格、年龄、计数、评分
- 时间:创建时间、更新时间、业务时间
- 标志位/枚举:is_deleted、status、type 等
不适合用结构化查询的字段:
- 需要做全文检索的长文本(标题、描述、评论等)
→ 应使用 match/match_phrase 等全文查询,详见“全文检索”章节。
term:精确匹配 #
term 查询不会做分词,也不会自动大小写转换,适合:
- keyword 字段
- 数值字段
- 布尔/枚举字段
典型用法(以伪 JSON 示意):
{
"query": {
"term": {
"status": "active"
}
}
}
建议:
- 对 text 字段做 term 查询通常是错误的(除非你非常明确知道底层分析行为)
- 业务 ID、编码类字段建议使用 keyword 类型并用 term 查询
terms:在一组值中匹配 #
terms 用于“IN 列表”场景:
{
"query": {
"terms": {
"status": ["active", "pending"]
}
}
}
典型场景:
- 过滤一组允许状态
- 从一批 ID 中筛选(注意列表长度与性能)
经验:非常长的 ID 列表(如几万、几十万)建议通过临时索引/标记字段等方式重构,而不是直接塞进 terms。
range:范围查询 #
range 用于数值或时间范围:
{
"query": {
"range": {
"created_at": {
"gte": "2024-01-01T00:00:00Z",
"lt": "2024-02-01T00:00:00Z"
}
}
}
}
常用比较符号:
gt/gte:大于(等于)lt/lte:小于(等于)
建议:
- 时间范围过滤几乎总是应该放在
filter中(不参与打分,可缓存) - 组合多个 range 时注意边界是否重叠/有缝
exists:字段存在性判断 #
exists 用于判断字段是否存在:
{
"query": {
"exists": {
"field": "email"
}
}
}
适合:
- 筛选“有值/缺失”的数据
- 区分“null/缺失” vs “有有效值”
小贴士:很多日志/埋点场景里,一部分字段是“有就有,没有就压根不出现在 JSON 里”,这时候
exists比“用特殊值占位再 term 查询”要自然得多。
和 bool/filter 结合使用 #
在实际查询中,这些结构化条件通常放到 bool.filter 里:
{
"query": {
"bool": {
"must": [
{ "match": { "title": "搜索" } }
],
"filter": [
{ "term": { "status": "active" } },
{ "range": { "created_at": { "gte": "now-7d/d" } } }
]
}
}
}
好处:
- 不参与
_score计算,语义更清晰(它们本来就是“硬过滤条件”) - 更容易被缓存,提高重复查询性能
组合示例:订单列表的典型过滤 #
一个稍微贴近业务的例子:电商后台的“订单列表”过滤:
{
"query": {
"bool": {
"must": [
{ "match": { "buyer_keywords": "北京 手机" } } // 主搜索词:全文检索
],
"filter": [
{ "term": { "status": "paid" }}, // 已支付
{ "terms": { "channel": ["app", "web"] }}, // 下单渠道
{
"range": { "order_time": { // 最近 30 天
"gte": "now-30d/d"
}}
},
{ "term": { "tenant_id": "t_123" }} // 多租户隔离
]
}
}
}
可以看到:
- 所有“业务约束/权限/时间范围”都在
filter里 - 只有真正影响排序/相关性的条件放在
must
典型实践小结 #
- 所有“业务约束/权限/状态/时间范围”优先用结构化查询表达,并放进 filter
- 尽量避免对 text 字段做 term/terms/range 查询,除非你确实要在分词后的 token 上做精确匹配
- 大批量 ID 过滤要关注 terms 的规模与性能,必要时用索引设计/标记字段重构问题
下一步可以继续阅读: