简体   繁体   English

Hibernate 带有枚举字段的搜索/Lucene 范围查询不返回任何结果

[英]Hibernate Search/Lucene range query with enum field doesn't return any results

When using Hibernate Search with the following enum field:使用 Hibernate 时搜索以下枚举字段:

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<>();
}

This is the enum:这是枚举:

public enum UserSkillLevel {
    JUNIOR,
    CONFIRMED,
    ADVANCED,
    EXPERT
}

When attempting to do a ranged query:尝试进行范围查询时:

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();

The problem is that no results are being returned, even if a user has a advanced or expert skill.问题是即使用户具有高级或专家技能,也不会返回任何结果。

Enums are indexes as strings by default, so the range you asked for is actually "every skill level whose name is alphabetically after the word 'ADVANCED'" .默认情况下,枚举是作为字符串的索引,因此您要求的范围实际上是“名称按字母顺序排列在单词 'ADVANCED' 之后的每个技能级别”

Thus I'd expect this to match everything instead;因此,我希望这可以匹配所有内容 maybe you forgot to reindex your data after you changed your mapping?也许您在更改映射后忘记重新索引数据?

Regardless... If you want to index your enums as their ordinal, implement a custom bridge:无论如何......如果您想将您的枚举索引为它们的序数,请实现一个自定义桥:

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 );
        }
    }
}

Then use it in your mapping:然后在您的映射中使用它:

public class UserSkill {
    @Enumerated
    @Field(bridge = @FieldBridge(impl = EnumAsIntegerBridge.class))
    private UserSkillLevel level;
}

public class User {
    @IndexedEmbedded
    private Set<UserSkill> skills = new HashSet<>();
}

And pass the ordinal instead of the enum to the query:并将序数而不是枚举传递给查询:

var q = queryBuilder.range().onField("skills.level").above(UserSkillLevel.ADVANCED.ordinal()).createQuery();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM