并在Lucene/Hibernate搜索中搜索子对象

并在Lucene/Hibernate搜索中搜索子对象,lucene,hibernate-search,Lucene,Hibernate Search,在我的web应用程序中,用户的能力数据可以存储为0-5级。使用Hibernate搜索(构建在Lucene之上),我希望构造一个查询,找到所有能力X最低排名为a的用户,例如排名为3的Java。此外,我希望在结果中提高排名,将排名4的用户放在排名3的用户之前。我觉得这应该是可能的,但我不知道如何组合子对象中的字段。我的数据结构如下(简化): 用户类 @Entity @Table(schema = "COMPETENCE", name = "users") @Indexed public class

在我的web应用程序中,用户的能力数据可以存储为0-5级。使用Hibernate搜索(构建在Lucene之上),我希望构造一个查询,找到所有能力X最低排名为a的用户,例如排名为3的Java。此外,我希望在结果中提高排名,将排名4的用户放在排名3的用户之前。我觉得这应该是可能的,但我不知道如何组合子对象中的字段。我的数据结构如下(简化):

用户类

@Entity
@Table(schema = "COMPETENCE", name = "users")
@Indexed
public class User{    
    @Id
    @Field(store = Store.YES, index = Index.UN_TOKENIZED)
    private Long id;

    @OneToMany(mappedBy = "user")
    @IndexedEmbedded
    private List<UserCompetence> competenceList= new ArrayList<UserCompetence>();

    // Snip: Other irrelevant fields and get/setters

}

当我试图构造一个强制某个能力和最低级别的查询时,它似乎会找到所有具有该能力的人以及具有指定级别的任何能力。如何使其仅返回具有正确usercapability子级的用户?我想我需要重新映射我的一些索引以使其工作。

使用当前映射,您尝试执行的操作是不可能的。用户的所有UserCapability实例都将作为同一用户文档的一部分进行索引。在本例中,数据是扁平的。如果您编写AND查询,您可能会在一个UserCompetency实例中获得一次能力命中,在另一个实例中获得一次最低级别命中。它们属于同一用户,但不属于同一用户实例的一部分。该用户实例将作为同一用户实例的一部分进行索引


一种方法是索引用户能力。然后,您可以使用和逻辑进行搜索,以匹配单个UserCapability实例。

您尝试的操作在当前映射中是不可能的。用户的所有UserCapability实例都将作为同一用户文档的一部分进行索引。在本例中,数据是扁平的。如果您编写AND查询,您可能会在一个UserCompetency实例中获得一次能力命中,在另一个实例中获得一次最低级别命中。它们属于同一用户,但不属于同一用户实例的一部分。该用户实例将作为同一用户实例的一部分进行索引


一种方法是索引用户能力。然后,您可以使用和逻辑搜索以匹配单个UserCapability实例。

最后,我得到了一个将两个字段合并为一个字段的自定义桥,然后使用短语搜索在合并字段中进行搜索

public class UserCompetenceBridge implements FieldBridge {
    @Override
    public void set(
            String name, Object value, Document document, LuceneOptions luceneOptions) {
        UserCompetence pc = (UserCompetence ) value;

        // Add competence level + competence id combined field for specific competence querying
        String lvl = pc.getLevel() == null ? "0" : pc.getLevel().toString();
        String comp = pc.getCompetence().getId().toString();

        String fieldValue = comp + SearchFields.FIELD_SEPERATOR + lvl;
        Field compLvl = new Field(SearchFields.COMPETENCE_LEVEL, fieldValue, Field.Store.NO, Field.Index.NOT_ANALYZED);
        compLvl.setBoost(luceneOptions.getBoost());
        document.add(compLvl);

        // Add competence names for free text search
        Field compName = new Field(SearchFields.COMPETENCE_NAME, pc.getCompetence().getName(), Field.Store.NO, Field.Index.ANALYZED);
        document.add(compName);

    }
}

@Entity
@Table(name = "user_competence")
@ClassBridge(impl = UserCompetenceBridge.class)
public class UserCompetence {

    @ManyToOne
    @JoinColumn(name = "user_id", referencedColumnName = "id")
    @ContainedIn
    private User user;

    @ManyToOne
    @JoinColumn(name = "competence_id", referencedColumnName = "id")
    private Competence competence;

    @Basic
    @Column(name = "competence_level")
    private Integer level;
}
像这样搜索level>x:

for (CompetenceParam cp : param.getCompetences()) {
    BooleanJunction or = qb.bool();
    for(int i = cp.getMinLevel(); i <= 5 ; i++){
        or = or.should(qb.phrase()
                .onField(SearchFields.COMPETENCE_LEVEL)
                .boostedTo(1 + i/5f)
                .sentence(cp.getCompetenceId() + " " + i)
                .createQuery());
    }
    queries.add(or.createQuery());
}
for(能力参数cp:param.getCompetencies()){
布尔连接or=qb.bool();

对于(int i=cp.getMinLevel();i,最后我得到了一个自定义桥,它将两个字段合并为一个字段,然后使用短语搜索在合并字段中进行搜索

public class UserCompetenceBridge implements FieldBridge {
    @Override
    public void set(
            String name, Object value, Document document, LuceneOptions luceneOptions) {
        UserCompetence pc = (UserCompetence ) value;

        // Add competence level + competence id combined field for specific competence querying
        String lvl = pc.getLevel() == null ? "0" : pc.getLevel().toString();
        String comp = pc.getCompetence().getId().toString();

        String fieldValue = comp + SearchFields.FIELD_SEPERATOR + lvl;
        Field compLvl = new Field(SearchFields.COMPETENCE_LEVEL, fieldValue, Field.Store.NO, Field.Index.NOT_ANALYZED);
        compLvl.setBoost(luceneOptions.getBoost());
        document.add(compLvl);

        // Add competence names for free text search
        Field compName = new Field(SearchFields.COMPETENCE_NAME, pc.getCompetence().getName(), Field.Store.NO, Field.Index.ANALYZED);
        document.add(compName);

    }
}

@Entity
@Table(name = "user_competence")
@ClassBridge(impl = UserCompetenceBridge.class)
public class UserCompetence {

    @ManyToOne
    @JoinColumn(name = "user_id", referencedColumnName = "id")
    @ContainedIn
    private User user;

    @ManyToOne
    @JoinColumn(name = "competence_id", referencedColumnName = "id")
    private Competence competence;

    @Basic
    @Column(name = "competence_level")
    private Integer level;
}
像这样搜索level>x:

for (CompetenceParam cp : param.getCompetences()) {
    BooleanJunction or = qb.bool();
    for(int i = cp.getMinLevel(); i <= 5 ; i++){
        or = or.should(qb.phrase()
                .onField(SearchFields.COMPETENCE_LEVEL)
                .boostedTo(1 + i/5f)
                .sentence(cp.getCompetenceId() + " " + i)
                .createQuery());
    }
    queries.add(or.createQuery());
}
for(能力参数cp:param.getCompetencies()){
布尔连接or=qb.bool();

对于(int i=cp.getMinLevel();我尝试为UserCapability编制索引,但重建索引所需的时间从30秒增加到了近一小时。如果我采用这种解决方案,将如何进行搜索?我仍然希望搜索用户对象,而不是用户权限对象。我还发现了在单个索引中组合字段的可能性,这似乎有些问题就其本身而言。您可以为用户和用户能力创建索引,并根据查询确定正确的索引。如何重建索引?海量索引器可以提高性能。或者,根据您的索引,仅依靠自动索引作为数据库更改的一部分。您可能希望查看@IndexedEmbedded#depth。具体取决于在对象图上,您可能索引过多。关于搜索结果。对于您提到的特定查询,您将搜索UserCapability实例,然后从那里导航到用户。我计划在夜间作业中使用mass indexer,同时依靠hibernate search在白天更新更改。我不太喜欢solu如果查询用户能力而不是用户,听起来可能会导致以后的麻烦,听起来可能会随着能力数量的增加而线性增加搜索时间,也会使用我的提升/标准值。我发现一个解决方案似乎足够有效:使用桥接器将能力和级别结合在一个字段中,t然后使用短语查询来搜索能力级别的确切实例。一个问题是,从桥接器中获取的相关实体的更改是否会更新索引?我尝试为UserCompetency编制索引,但重建索引所需的时间从30秒增加到近一个小时。如果我使用该解决方案,将如何进行搜索?我仍然会搜索用户对象而不是用户能力对象。我还发现了在单个索引中组合字段的可能性,这本身似乎有一些问题。您可以为用户和用户能力创建索引,并根据查询确定正确的索引。如何重建索引?海量索引器可以提高性能nce。或者,根据您的索引,只是依靠自动索引作为数据库更改的一部分。您可能希望查看@IndexedEmbedded#depth。根据您的对象图,您可能索引过多。关于搜索结果。对于您提到的特定查询,您将搜索UserCapability实例,然后从我在那里。我计划在夜间工作中使用大规模索引器,同时依靠hibernate搜索在白天更新更改。我不太喜欢查询用户能力而不是用户能力的解决方案,这听起来可能会导致以后的麻烦,听起来它会随着能力的数量线性增加搜索时间,而且还会增加o与我的boost/norm值有关的问题。我找到了一个似乎足够有效的解决方案:使用桥接器在单个字段中组合能力和级别,然后使用短语查询来搜索能力级别的确切实例。一个问题是,对从桥接器获取的相关实体的更改是否会更新索引?