如何通过Hibernate Search 6在Elasticsearch中搜索索引实体所有字段
解决方案:让Hibernate Search支持搜索所有@FullTextField字段
问题背景
现有基于Hibernate Search 6.2.2和Elasticsearch 8.10的查询方法,仅能固定搜索addresses.address_key字段。需要修改为支持任意格式的查询字符串(如first_name:john),并覆盖所有标注@FullTextField的字段。
原始代码
查询方法
public Page<Employee> searchEmployee(String queryString) { try { SearchSession searchSession = Search.session(entityManager); SearchResult<Employee> searchResult = searchSession.search(Employee.class) .extension(ElasticsearchExtension.get()) .where(f -> f.simpleQueryString().fields("addresses.address_key").matching(queryString)) .fetch(Math.toIntExact(page.getOffset()), page.getPageSize()); Page<Employee> pageResult = new PageImpl<>(searchResult.hits(), page, searchResult.total().hitCount()); return pageResult; } catch (SearchException pe) { throw pe; } }
索引实体类
@Indexed(index = "employee") public class Employee { @FullTextField(name = "employee_key") private String employeeKey; @FullTextField(name = "first_name") private String firstName; @IndexedEmbedded(includeEmbeddedObjectId = true, includeDepth = 2) private Address addresses; } public class Address { @FullTextField(name = "address_key") private String addressKey; @FullTextField(name = "street_name") private String streetName; }
修改方案
方案1:显式指定所有目标字段
直接在查询中列出所有@FullTextField对应的字段路径,同时补充缺失的page方法参数:
public Page<Employee> searchEmployee(String queryString, Pageable page) { try { SearchSession searchSession = Search.session(entityManager); SearchResult<Employee> searchResult = searchSession.search(Employee.class) .extension(ElasticsearchExtension.get()) .where(f -> f.simpleQueryString() .fields("employee_key", "first_name", "addresses.address_key", "addresses.street_name") .matching(queryString)) .fetch(Math.toIntExact(page.getOffset()), page.getPageSize()); Page<Employee> pageResult = new PageImpl<>(searchResult.hits(), page, searchResult.total().hitCount()); return pageResult; } catch (SearchException pe) { throw pe; } }
方案2:配置实体默认搜索字段
在Employee类的@Indexed注解中配置默认搜索字段集合,查询时无需显式指定字段,代码更简洁:
修改后的实体类
@Indexed(index = "employee", defaultSearchFields = { "employee_key", "first_name", "addresses.address_key", "addresses.street_name" }) public class Employee { @FullTextField(name = "employee_key") private String employeeKey; @FullTextField(name = "first_name") private String firstName; @IndexedEmbedded(includeEmbeddedObjectId = true, includeDepth = 2) private Address addresses; } public class Address { @FullTextField(name = "address_key") private String addressKey; @FullTextField(name = "street_name") private String streetName; }
修改后的查询方法
public Page<Employee> searchEmployee(String queryString, Pageable page) { try { SearchSession searchSession = Search.session(entityManager); SearchResult<Employee> searchResult = searchSession.search(Employee.class) .extension(ElasticsearchExtension.get()) .where(f -> f.simpleQueryString().matching(queryString)) .fetch(Math.toIntExact(page.getOffset()), page.getPageSize()); Page<Employee> pageResult = new PageImpl<>(searchResult.hits(), page, searchResult.total().hitCount()); return pageResult; } catch (SearchException pe) { throw pe; } }
关键说明
- 两种方案都支持用户传入带字段限定的查询字符串(如
first_name:john),Simple Query String语法会自动识别并搜索指定字段;若用户未指定字段(如john),则会搜索所有配置的字段 - 方案1无需修改实体类,但后续新增
@FullTextField字段时,需要同步更新查询代码中的字段列表 - 方案2查询代码简洁,新增字段时只需更新实体类的
defaultSearchFields配置,维护更方便 - 原代码中缺失
page方法参数,已补充到方法签名中避免编译错误
内容的提问来源于stack exchange,提问作者Gaurav
相关产品推荐
相关产品推荐

