在我的网络应用程序中,用户的能力数据可以按0-5排名存储。使用Hibernate搜索(建立在Lucene之上),我希望构建一个查询,查找具有最低排名A的权限X的所有用户,例如排名为3的Java。此外,我希望在结果中提高排名在排名为3的用户之前放置排名为4的用户。我觉得这应该是可能的,但我无法弄清楚如何组合子对象中的字段。我的数据结构看起来像这样(简化):
User.class
@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
}
UserCompetence.class
@Entity
@Table(name = "user_competence")
public class Competence {
@ManyToOne
@JoinColumn(name = "user_id", referencedColumnName = "id")
@NotNull
@ContainedIn
private User user;
@ManyToOne
@JoinColumn(name = "competence_id", referencedColumnName = "id")
@NotNull
@IndexedEmbedded
private Competence competence;
@Basic
@Field(index = Index.UN_TOKENIZED, store = Store.YES)
@NumericField
private Integer level;
// Snip: Other irrelevant fields and get/setters
}
@Entity()
@Table(name = "competence")
public class Competence{
@Column(name = "name")
@Field(index = Index.TOKENIZED, store = Store.YES)
private String name;
// Snip: Other irrelevant fields and get/setters
}
当我尝试构建一个强制某个能力和最低级别的查询时,它似乎发现所有具有该能力的人和任何具有指定级别的能力。如何使其仅返回具有正确UserCompetence儿童的用户?我怀疑我需要重新映射一些索引才能使其正常工作。
答案 0 :(得分:2)
您当前的映射无法尝试执行的操作。用户的所有 UserCompetence 实例将被编入索引,作为同一用户文档的一部分。这种情况下的数据是flatend。如果你编写AND查询,你可能会在一个 UserCompetence 实例中获得一个权限,在另一个实例中获得一个最低级别。它们属于同一个用户,但不属于相同的用户实例,将被编入索引作为同一 UserCompetence 实例的一部分。
一种方法是索引 UserCompetence 。然后,您可以使用AND逻辑进行搜索,以匹配单个 UserCompetence 实例。
答案 1 :(得分:2)
最后,我得到了一个自定义网桥,将两个字段合二为一,然后使用短语搜索在组合字段中进行搜索。
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;
}
搜索级别&gt; 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());
}
这可以提升高水平的人,而且看起来非常快。