主要记录项目中使用的es高阶查询语法,es版本7.x
基于以下相关依赖
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
</dependency>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
</dependency>
一、首先构建一个查询请求即SearchRequest
SearchRequest构造函数包含索引名称以及SearchSourceBuilder
SearchSourceBuilder的主要方法
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
1、fetchSource
fetchSource既可以指定返回的字段名称,也可以指定排除的字段名称,一般我们指定我们所需要返回的字段就够了
searchSourceBuilder.fetchSource("需要的字段数组",null)
2、BoolQueryBuilder
是 Elasticsearch 中用于构建 布尔查询(Boolean Query) 的核心工具类,它允许通过逻辑组合多个查询条件(如 must
、should
、must_not
、filter
)
-
must
: 文档必须匹配这些条件,且会影响相关性评分(_score
)。 -
should
: 文档满足这些条件会增加相关性评分,若没有must
,则至少一个should
需匹配(可通过minimum_should_match
控制)。 -
must_not
: 文档必须不匹配这些条件,不参与评分(常用于排除特定结果)。 -
filter
: 过滤文档(不计算评分),但结果可被缓存,适合性能敏感的场景。以电商项目背景为例,
在Es中查询商品为 上架 且 库存充足 且 商品类别 不为 实物商品 且配送方式 为 无需快递 且价格区间在100-500区间 的商品
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder(); boolQueryBuilder.filter(QueryBuilders.termsQuery(EsConstant.STATUS, 1)) // 1代表上架boolQueryBuilder.filter(QueryBuilders.termQuery(EsConstant.HAS_STOCK, 1)) // 1代表库存充足 boolQueryBuilder.mustNot(QueryBuilders.termQuery(EsConstant.MOLD, 1))//1代表实物 boolQueryBuilder.filter(QueryBuilders.termsQuery(EsConstant.DELIVERIES,1)) //1代表无需快递配送 boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(100).lte(500))//价格区间 searchSourceBuilder.query(boolQueryBuilder);
关于must和filter的选择,
must
和 filter
它们的核心区别在于是否影响文档的 相关性评分(_score
) 以及是否对结果进行缓存。在电商场景中,选择使用 must
还是 filter
需要根据业务需求决定:
核心区别
特性 | must |
filter |
---|---|---|
是否影响评分 | ✅ 影响(计算相关性得分) | ❌ 不影响(仅过滤,评分固定为 1.0 ) |
是否缓存结果 | ❌ 不缓存 | ✅ 缓存(性能更高) |
适用场景 | 需要相关性排序的条件(如关键词匹配) | 纯过滤条件(如价格、库存、分类筛选) |
举个例子,如果搜索的是商品名称关键字,这种情况就需要用must。
如果搜索的是分类等这种确定性的指标,就可以用filter。
3、排序
此处采用的是脚本方式
// 构建脚本
String scriptCode = "double earthRadius = 6371; " + // 地球半径(单位:千米)
"double lat = doc['latitude'].value; " +
"double lon = doc['longitude'].value; " +
"double dLat = Math.toRadians(params.targetLat - lat); " +
"double dLon = Math.toRadians(params.targetLon - lon); " +
"double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + " +
"Math.cos(Math.toRadians(lat)) * Math.cos(Math.toRadians(params.targetLat)) * " +
"Math.sin(dLon / 2) * Math.sin(dLon / 2); " +
"double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); " +
"return earthRadius * c;"; // 返回距离(单位:千米)
// 创建脚本对象
Script script = new Script(ScriptType.INLINE, "painless", scriptCode,
Collections.singletonMap("targetLat", 39.9055), // 用户纬度
Collections.singletonMap("targetLon", 116.3976)); // 用户经度
// 构建 ScriptSortBuilder
ScriptSortBuilder sortBuilder = new ScriptSortBuilder(script, ScriptSortBuilder.ScriptSortType.NUMBER)
.order(SortOrder.ASC) // 升序排列(距离由近到远)
.unit("km"); // 单位:千米(可选值:km, mi)
.sort(sortBuilder)
searchSourceBuilder.sort(sortBuilder)
4、构建最终的SearchRequest
SearchRequest searchRequest = SearchRequest(new String[]{EsIndexEnum.PRODUCT.value()},searchSourceBuilder);
response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);