如何在Hibernate Search中将范围查询与关键字查询结合起来?

时间:2020-06-10 10:45:38

标签: java hibernate lucene hibernate-search

给出此域模型:

class User { // <- this is the root entity
    @IndexedEmbedded
    private Set<UserSkill> skills = new HashSet<>();
}

class UserSkill {
    @IndexedEmbedded
    private Skill skill;

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

class Skill {
    @Field
    private String name;
}

如何结合使用范围查询和术语查询来搜索具有给定级别特定技能的用户?

我尝试使用此查询来查找具有高级React技能的用户:

var q = new BooleanQuery.Builder();
q.add(queryBuilder.keyword().onField("skills.skill.name").matching("React").createQuery(), BooleanClause.Occur.MUST);
q.add(queryBuilder.range().onField("skills.level").above(UserSkillLevel.ADVANCED.ordinal()).createQuery(), BooleanClause.Occur.MUST);
var finalQuery = q.build();

返回的内容:

  • 具有React技术(无论级别如何)的用户 AND
  • 具有高级技能或更高技能的用户(与技能名称无关)

我希望它返回什么:

  • 具有更高或更高的React技能的用户。

1 个答案:

答案 0 :(得分:0)

在查询中,您从未提到两个约束(技能名称和技能级别)必须应用于同一技能。这就是为什么您得到此结果。

在Hibernate Search 5中,不支持这种“联接”。最好的办法是在单个字段(连接的字段)中索引技能名称和技能等级,但这有点麻烦。

在Hibernate Search 6中,对 nested 字段的支持可以解决此问题。但是,Hibernate Search 6的API却大不相同。

这是如何在Hibernate Search 6中实现所需的功能。

@Indexed
class User {
    @IndexedEmbedded(storage = ObjectStorage.NESTED) // Notice this change
    private Set<UserSkill> skills = new HashSet<>();
}

class UserSkill {
    @IndexedEmbedded
    private Skill skill;

    @Enumerated
    @GenericField(valueBridge = @ValueBridge(impl = EnumAsIntegerBridge.class)) // This changed too
    private UserSkillLevel level;
}

class Skill {
    @FullTextField(analyzer = "standard") // You will have to define this analyzer, see the getting started guide
    private String name;
}

// New implementation of your bridge
class EnumAsIntegerValueBridge implements ValueBridge<Enum<?>, Integer> {
    @Override
    public Integer toIndexedValue(Enum<?> enum) {
        return enum.ordinal();
    }
}

然后查询:

List<User> hits = Search.session(entityManager).search(User.class)
        .where(f -> f.nested().onField("skills").nest(f.bool()
                .must(f.match().field("skills.skill.name").matching("React"))
                .must(f.range().field("skills.level").atLeast(UserSkillLevel.ADVANCED))))
        .fetchHits(20);

请注意,您将需要更新依赖项(groupId,artifactId和版本)。您可能想先看看getting started guide