Hibernate Search 6:聚合字段支持大小写不敏感查询且保留原大小写聚合结果
解决方案:通过多字段映射实现大小写不敏感查询+原大小写聚合
要同时满足大小写不敏感查询和保留原大小写聚合结果,你需要将查询和聚合的逻辑拆分到两个不同的字段上:一个字段用于存储原格式字符串(供聚合使用),另一个字段存储小写标准化后的字符串(供查询使用)。
核心原因
你之前的做法是在同一个字段上同时应用小写标准化器和聚合配置,这会导致索引中存储的是小写后的内容,聚合自然只能返回小写结果。projectable(Projectable.YES)仅控制是否能从索引中投影该字段的值,但投影的也是标准化后的小写内容,而非实体的原字段值。
具体实现步骤
1. 定义两个字段模板(或直接在实体字段上配置双字段)
如果使用字段模板,分别定义聚合用模板和查询用模板:
// 聚合用模板:存储原字符串,支持聚合和投影 indexSchemaObjectField.fieldTemplate("aggregable-original", f -> f.asString() .aggregable(Aggregable.YES) .projectable(Projectable.YES) ).multiValued(); // 查询用模板:存储小写标准化后的字符串,仅用于查询 indexSchemaObjectField.fieldTemplate("lowercase-query", f -> f.asString() .normalizer("lowercase") ).multiValued();
2. 在实体字段上应用双字段配置
在需要实现该功能的实体字段上,同时绑定两个模板(或直接添加两个@KeywordField注解):
// 原字段绑定聚合模板,同时创建一个后缀为_lower的查询字段 @KeywordField(templateName = "aggregable-original") @KeywordField(templateName = "lowercase-query", name = "{fieldName}_lower") private String yourFieldName;
3. 查询与聚合分别对应不同字段
- 查询时,使用小写标准化后的字段(
yourFieldName_lower)实现大小写不敏感匹配 - 聚合时,使用原格式字段(
yourFieldName)获取保留原大小写的结果
示例代码:
// 构建查询与聚合 SearchResult<YourEntity> searchResult = searchSession.search(YourEntity.class) // 针对小写字段做匹配,实现大小写不敏感查询 .where(f -> f.match().field("yourFieldName_lower").matching("UserInput")) // 针对原字段做聚合,得到原大小写的结果 .aggregation("fieldAggregation", f -> f.terms().field("yourFieldName")) .fetch(20); // 获取聚合结果(原大小写) TermsAggregationResult aggregation = searchResult.aggregation("fieldAggregation"); for (TermsBucket<?> bucket : aggregation.buckets()) { String originalValue = bucket.key(); // 原大小写的聚合值 long count = bucket.docCount(); // 处理聚合结果 }
补充说明
如果只是需要在查询结果的详情中展示原字段值,而非聚合时保留,也可以直接通过fetchHits()投影实体本身,但聚合逻辑仍需依赖单独的原格式字段——因为聚合是完全基于索引存储内容的操作,无法从原实体直接获取聚合数据。
内容的提问来源于stack exchange,提问作者Archie Goodwin
相关产品推荐
相关产品推荐

