一、sort 排序
Elasticsearch 的 sort 参数用于控制搜索结果的排序方式,支持按字段值、相关性评分(_score)或自定义脚本进行排序。
1.1 基础排序语法
-
按单个字段排序
GET /index/_search { "sort": [ { "price": "desc" } // 按 price 字段降序排列 ] } -
按相关性评分排序
默认情况下,结果按 _score(相关性评分)降序排列。若需显式指定:{ "sort": [ { "_score": "desc" } ] } -
指定排序模式(多值字段)
当字段为数组(多值字段)时,需通过 mode 指定排序依据的取值方式:- min:取最小值
- max:取最大值
- avg:取平均值
- sum:取总和
- median:取中位数
{ "sort": [ { "prices": { "order": "asc", "mode": "avg" // 按多值字段的平均值升序排序 } } ] }
1.2 排序类型
- 字段值排序
- 最常见的排序方式,基于字段值排序。
{ "sort": [ { "price": { "order": "asc" } } ] }
- 最常见的排序方式,基于字段值排序。
- 特殊排序
- _score:按相关性评分排序
{ "query": { "match": { "title": "elasticsearch" } }, "sort": [ "_score", { "date": "desc" } ] } - _doc:按索引顺序排序(性能最高)
{ "sort": "_doc" } - _shard_doc:按分片文档顺序排序
{ "sort": "_shard_doc" }
- _score:按相关性评分排序
- 多值字段排序
- 当字段有多个值时,可指定多个排序条件,按优先级依次排序:
{ "sort": [ { "date": "desc" }, // 第一优先级:日期降序 { "_score": "desc" }, // 第二优先级:相关性评分降序 { "price": "asc" } // 第三优先级:价格升序 ] }
1.3 特殊字段的排序处理
-
文本字段(text)
默认情况下,text 类型字段无法直接排序(因其被分词为多个词项)。需使用 keyword 子字段:{ "sort": [ { "title.keyword": "asc" } // 按未分词的原始文本排序 ] } -
日期字段
Elasticsearch 自动识别日期格式,支持按时间排序:{ "sort": [ { "create_time": "desc" } ] } -
地理坐标字段
按距离某个坐标的远近排序:{ "sort": [ { "_geo_distance": { "location": { "lat": 40.73, "lon": -74.1 }, // 目标坐标 "order": "asc", // 按距离升序 "unit": "km" // 距离单位(km/mi) } } ] }
1.4 处理缺失值(missing参数)
当字段缺失时,可指定默认值或排序规则:
- missing: “_last”:缺失值的文档排在最后。
- missing: “_first”:缺失值的文档排在最前。
- missing: 100:为缺失字段赋予默认值(数值或日期)。
{
"sort": [
{
"price": {
"order": "asc",
"missing": "_last" // 缺失 price 的文档排在最后
}
}
]
}
1.5 脚本排序
使用 Painless 脚本动态计算排序值:
{
"sort": [
{
"_script": {
"type": "number",
"script": {
"source": "doc['price'].value * params.factor", // 按价格乘以系数排序
"params": { "factor": 0.8 }
},
"order": "desc"
}
}
]
}
1.6 嵌套对象排序
-
基本嵌套排序
{ "sort": [ { "comments.date": { "order": "desc", "nested": { "path": "comments" } } } ] } -
带过滤的嵌套排序
{ "sort": [ { "comments.date": { "order": "asc", "nested": { "path": "comments", "filter": { "term": { "comments.verified": true } } } } } ] }
1.7 性能优化建议
- 避免对 text 字段排序
- 使用 keyword 子字段或开启 fielddata(需谨慎,可能占用内存)。
- 使用 doc_values 优化数值/日期排序
- Elasticsearch 默认对非文本字段启用 doc_values,加速排序和聚合。
- 限制排序字段数量
- 多字段排序会增加计算开销。
二、_source 返回字段控制
在 Elasticsearch 的 DSL 中,_source 参数用于控制返回的原始文档内容,类似于 SQL 中的 SELECT 字段列表。合理使用 _source 可以显著减少网络传输开销和提高查询性能。
2.1 _source 的核心功能
_source 是 Elasticsearch 存储的原始 JSON 文档。默认情况下,当你执行搜索时,Elasticsearch 会返回完整的 _source 文档。
-
返回完整文档(默认行为):
- 返回所有字段(_source 包含完整 JSON 文档)。
GET /products/_search { "query": { "match_all": {} } } -
过滤返回字段:
{ "_source": ["title", "price"], // 只返回 title 和 price 字段 "query": { ... } } -
排除特定字段:
{ "_source": { "excludes": ["description", "tags"] // 排除 description 和 tags }, "query": { ... } }
2.2 为什么需要控制 _source
- 减少网络传输:只返回需要的字段。
- 提高查询性能:减少数据序列化/反序列化开销。
- 安全性:隐藏敏感字段。
- 灵活性:可以重命名字段或添加脚本字段。
2.3 _source 的高级用法
-
动态字段过滤(Wildcards)
- 使用通配符匹配字段名:
{ "_source": ["user.*", "*.timestamp"], // 返回所有 user 子字段和以 .timestamp 结尾的字段 "query": { ... } } -
嵌套字段控制
- 指定嵌套对象中的子字段:
{ "_source": ["author.name", "comments.content"], // 返回嵌套字段 "query": { ... } } -
字段重命名(需结合 Script Fields)
- 通过脚本修改返回字段名(非原生支持,需额外处理):
{ "_source": ["original_field"], "script_fields": { "new_name": { "script": { "source": "doc['original_field'].value" } } } }
2.4 性能优化建议
-
限制返回字段
- 适用场景:只需部分字段时(如前端列表页)。
- 示例:
{ "_source": ["id", "name", "price"], "query": { ... } }
-
禁用 _source(谨慎使用)
- 适用场景:仅需聚合结果或文档 ID 时。
- 注意:禁用后无法获取原始文档内容!
{ "_source": false, // 不返回 _source "query": { ... } }
-
结合 docvalue_fields 获取存储列
- 适用场景:对非文本字段(如数值、日期)高效读取。
- 示例:
{ "docvalue_fields": ["price", "create_time"], // 从列存中获取 "query": { ... } }
三、script_fields 脚本字段
在 Elasticsearch 的 DSL 中,script_fields 允许你通过脚本动态计算并返回新字段,这些字段不会存储在索引中,而是在查询时实时生成。
3.1 script_fields 基础
-
基本语法结构
GET /index/_search { "script_fields": { "新字段名": { // 自定义字段名称 "script": { "source": "脚本逻辑", // Painless 脚本 "params": { ... } // 可选参数 } } } } -
script_fields 的核心功能
- 动态计算字段:基于已有字段值,通过脚本生成新字段。
- 不修改原始文档:仅在查询结果中临时添加字段。
- 支持复杂逻辑:使用 Painless 脚本语言实现条件判断、数学运算等。
3.2 基本用法
-
数值计算
{ "script_fields": { "total_price": { "script": { "source": "doc['price'].value * doc['quantity'].value" } } } } -
条件判断
{ "script_fields": { "discount_label": { "script": { "source": """ if (doc['price'].value > 1000) { return 'premium'; } else { return 'standard'; } """ } } } } -
字符串处理
{ "script_fields": { "short_title": { "script": { "source": "doc['title'].value.substring(0, 10) + '...'" // 截取前10个字符 } } } } -
日期格式化
{ "script_fields": { "date_formatted": { "script": { "source": """ LocalDateTime.ofInstant( Instant.ofEpochMilli(doc['timestamp'].value.millis), ZoneId.of('UTC') ).format(DateTimeFormatter.ISO_DATE) """ } } } }
3.3 高级用法
-
使用参数(params)
{ "script_fields": { "price_with_tax": { "script": { "source": "doc['price'].value * params.tax_rate", "params": { "tax_rate": 1.2 } } } } } -
处理空值
{ "script_fields": { "safe_division": { "script": { "source": """ if (doc['divisor'].size() == 0 || doc['divisor'].value == 0) { return 0; } return doc['dividend'].value / doc['divisor'].value; """ } } } } -
访问嵌套字段
{ "script_fields": { "author_first_name": { "script": { "source": "doc['author.name'].value.splitOnToken(' ')[0]" } } } }
3.4 性能优化建议
- 避免高频使用:脚本计算会显著增加查询延迟。
- 优先使用 Doc Values:对非文本字段使用 doc[‘field’].value 比 _source.field 更高效。
- 参数化脚本:通过 params 传递变量,避免硬编码。
- 缓存脚本:对重复使用的脚本启用 “lang”: “painless” 并利用缓存。
四、highlight 高亮显示
在 Elasticsearch 的 DSL 中,highlight 功能用于标记搜索结果中与查询条件匹配的文本片段,通常以高亮、加粗或颜色变化的形式展示,帮助用户快速定位关键内容。
4.1 highlight 的核心功能
- 标记匹配文本:在返回的字段值中突出显示匹配的关键词。
- 支持多字段:可同时对多个字段进行高亮。
- 自定义样式:通过 HTML 标签或自定义标记包裹匹配内容。
4.2 基础用法
-
基本语法结构
GET /index/_search { "query": { ... }, // 查询条件 "highlight": { "fields": { "字段名": { ... } // 高亮配置 } } } -
简单示例
{ "query": { "match": { "content": "Elasticsearch" } }, "highlight": { "fields": { "content": {} } } }
4.3 常见配置参数
| 参数 | 作用 | 示例值 |
|---|---|---|
| pre_tags | 匹配文本的前置标签(如 <em>) | ["<strong>"] |
| post_tags | 匹配文本的后置标签(如 </em>) | ["</strong>"] |
| number_of_fragments | 返回的文本片段数量(默认 5) | 3 |
| fragment_size | 每个片段的最大字符数(默认 100) | 150 |
| no_match_size | 无匹配时返回的字段前缀字符数(默认 0) | 50 |
| fragment_size | 是否仅高亮查询中明确指定的字段(默认 true) | false |
4.4 典型使用场景
-
基础高亮(HTML 标签)
{ "query": { "match": { "content": "elasticsearch" } }, "highlight": { "fields": { "content": {} // 使用默认 <em> 标签 } } } -
自定义高亮标签
{ "highlight": { "pre_tags": ["<mark>"], "post_tags": ["</mark>"], "fields": { "title": {}, "description": {} } } } -
控制片段数量和长度
{ "highlight": { "fields": { "content": { "number_of_fragments": 3, // 返回3个片段 "fragment_size": 200 // 每个片段200字符 } } } } -
高亮所有字段(忽略查询字段限制)
{ "highlight": { "require_field_match": false, // 高亮所有匹配字段 "fields": { "*": {} } // 通配符匹配所有字段 } }
4.5 高级功能
-
多字段差异化配置
{ "highlight": { "fields": { "title": { "pre_tags": ["<b>"], "post_tags": ["</b>"] }, "content": { "number_of_fragments": 0 } // 返回完整字段(不分片) } } } -
边界字符高亮(Boundary Scanners)
- 控制分片边界(按句子或单词划分):
{ "highlight": { "fields": { "content": { "boundary_scanner": "sentence", // 按句子分片 "boundary_scanner_locale": "zh-CN" // 中文分句 } } } } -
命中词排序
- 按匹配词出现顺序排序片段:
{ "highlight": { "order": "score", // 按相关性排序 "fields": { "content": {} } } }
4.6 性能优化建议
- 限制高亮字段:避免对大型文本字段(如日志内容)高亮。
- 合理设置 fragment_size:根据前端展示需求调整片段长度。
- 谨慎使用通配符:“*” 可能意外高亮不必要字段。
3445

被折叠的 条评论
为什么被折叠?



