使用枚举字段的 Hibernate Search/Lucene 范围查询没有 return 任何结果
Hibernate Search/Lucene range query with enum field doesn't return any results
使用具有以下枚举字段的 Hibernate Search 时:
public class UserSkill {
@Enumerated
@Field
private UserSkillLevel level; // <- this is the field we're using on the ranged query
}
public class User { // <- this is the root class
@IndexedEmbedded
private Set<UserSkill> skills = new HashSet<>();
}
这是枚举:
public enum UserSkillLevel {
JUNIOR,
CONFIRMED,
ADVANCED,
EXPERT
}
尝试进行范围查询时:
var fullTextEntityManager = Search.getFullTextEntityManager(entityManager);
var queryBuilder = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity(User.class).get();
var bq = new BooleanQuery.Builder();
var q = queryBuilder.range().onField("skills.level").above(UserSkillLevel.ADVANCED).createQuery();
bq.add(q, BooleanClause.Occur.MUST);
return fullTextEntityManager.createFullTextQuery(bq.build(), User.class).getResultList();
问题是没有返回任何结果,即使用户具有高级或专家技能。
枚举默认是字符串索引,所以你要求的范围实际上是"every skill level whose name is alphabetically after the word 'ADVANCED'".
因此我希望它能匹配 所有东西;也许您在更改映射后忘记重新索引数据?
无论如何......如果你想将你的枚举索引为它们的序号,实现一个自定义桥:
public class EnumAsIntegerBridge implements MetadataProvidingFieldBridge {
@Override
public void configureFieldMetadata(String name, FieldMetadataBuilder builder) {
builder.field( name, FieldType.INTEGER );
}
@Override
public void set(String name, Object value, Document document, LuceneOptions luceneOptions) {
Enum<?> enum = (Enum<?>) value;
if ( enum != null ) {
luceneOptions.addNumericFieldToDocument( name, enum.ordinal(), document );
}
}
}
然后在您的映射中使用它:
public class UserSkill {
@Enumerated
@Field(bridge = @FieldBridge(impl = EnumAsIntegerBridge.class))
private UserSkillLevel level;
}
public class User {
@IndexedEmbedded
private Set<UserSkill> skills = new HashSet<>();
}
并将序号而不是枚举传递给查询:
var q = queryBuilder.range().onField("skills.level").above(UserSkillLevel.ADVANCED.ordinal()).createQuery();
使用具有以下枚举字段的 Hibernate Search 时:
public class UserSkill {
@Enumerated
@Field
private UserSkillLevel level; // <- this is the field we're using on the ranged query
}
public class User { // <- this is the root class
@IndexedEmbedded
private Set<UserSkill> skills = new HashSet<>();
}
这是枚举:
public enum UserSkillLevel {
JUNIOR,
CONFIRMED,
ADVANCED,
EXPERT
}
尝试进行范围查询时:
var fullTextEntityManager = Search.getFullTextEntityManager(entityManager);
var queryBuilder = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity(User.class).get();
var bq = new BooleanQuery.Builder();
var q = queryBuilder.range().onField("skills.level").above(UserSkillLevel.ADVANCED).createQuery();
bq.add(q, BooleanClause.Occur.MUST);
return fullTextEntityManager.createFullTextQuery(bq.build(), User.class).getResultList();
问题是没有返回任何结果,即使用户具有高级或专家技能。
枚举默认是字符串索引,所以你要求的范围实际上是"every skill level whose name is alphabetically after the word 'ADVANCED'".
因此我希望它能匹配 所有东西;也许您在更改映射后忘记重新索引数据?
无论如何......如果你想将你的枚举索引为它们的序号,实现一个自定义桥:
public class EnumAsIntegerBridge implements MetadataProvidingFieldBridge {
@Override
public void configureFieldMetadata(String name, FieldMetadataBuilder builder) {
builder.field( name, FieldType.INTEGER );
}
@Override
public void set(String name, Object value, Document document, LuceneOptions luceneOptions) {
Enum<?> enum = (Enum<?>) value;
if ( enum != null ) {
luceneOptions.addNumericFieldToDocument( name, enum.ordinal(), document );
}
}
}
然后在您的映射中使用它:
public class UserSkill {
@Enumerated
@Field(bridge = @FieldBridge(impl = EnumAsIntegerBridge.class))
private UserSkillLevel level;
}
public class User {
@IndexedEmbedded
private Set<UserSkill> skills = new HashSet<>();
}
并将序号而不是枚举传递给查询:
var q = queryBuilder.range().onField("skills.level").above(UserSkillLevel.ADVANCED.ordinal()).createQuery();