我有两个对象 - 一个Document
对象和一个Hit
对象:
Document
id
description
hits (Collection of type Hits)
...
Hit
documentId (Type Document)
date
...
我试图创建一个搜索文档描述的Hibernate Search查询,然后按给定日期范围内的点击次数对结果进行排序。
我在如何做到这一点时遇到了一些麻烦。我已经查看了this,但它考虑了点击总数,并且不允许动态日期范围查询,因为桥接字段的更新与日期无关。
我目前有一个Document
对象的索引,搜索description
正常工作。我想我可能需要为Hit
对象创建索引,针对日期范围运行查询,按documentId
分组,然后使用搜索的术语运行第二个查询反对Document
索引。
鉴于这种策略,我仍然不确定如何:
documentId
我的猜测是我需要从Hits
索引中获取所有结果(使用某种类型的分面逻辑进行分组/排序?),然后匹配documentId
/ term并处理分页在第二个查询中。我只是不确定在使用QueryBuilder界面构建查询时所有这些看起来如何,或者如果有一种完全不同的方法来解决这个问题我还没有想到了。
更新
public class DateRangeDownloadsFieldComparator extends FieldComparator<Integer> {
class DownloadsParser implements FieldCache.IntParser {
@Override
public int parseInt(String string) {
/*
* What do I pass here and what do I do with it?
* Ideally, I would pass the downloads collection and return the size of the
* collection where the download appears within the provided date range, but
* passing a collection here does nothing, as it's silently ignored.
*/
return 0;
}
}
private Calendar startDate;
private Calendar endDate;
private final int[] fieldValues;
private int bottom;
private int[] currentReaderValues;
public DateRangeDownloadsFieldComparator(int numHits, Calendar startDate, Calendar endDate) {
super();
this.startDate = startDate;
this.endDate = endDate;
fieldValues = new int[numHits];
}
@Override
public int compare(int slot1, int slot2) {
return compareValues(fieldValues[slot1], fieldValues[slot2]);
}
@Override
public int compareBottom(int doc) throws IOException {
int currentDoc = currentReaderValues[doc];
return compareValues(bottom, currentDoc);
}
@Override
public int compareValues(Integer v1, Integer v2) {
if (v1 > v2) {
return 1;
}
else if (v1 < v2) {
return -1;
}
else {
return 0;
}
}
@Override
public void copy(int slot, int doc) throws IOException {
int v1 = currentReaderValues[doc];
fieldValues[slot] = v1;
}
@Override
public void setBottom(int slot) {
bottom = fieldValues[slot];
}
@Override
public void setNextReader(IndexReader reader, int docBase) throws IOException {
currentReaderValues = FieldCache.DEFAULT
.getInts(reader, "downloads", new DownloadsParser());
}
@Override
public Integer value(int slot) {
return fieldValues[slot];
}
}
更新2
文件实体
@Entity
@Table(name = "documents")
@Indexed(index = "documents")
public class EDocument {
public static final String FIELD_NAME = "name";
public static final String FIELD_CREATED = "created";
public static final String FIELD_DESCRIPTION = "description";
@Id
@GeneratedValue
@Column(name = "id")
private Long id;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "created")
@Field(name = FIELD_CREATED)
private Calendar created;
@Column(name = "name")
@Field(name = FIELD_NAME)
private String name;
@Column(name = "description")
@Field(name = FIELD_DESCRIPTION)
private String description;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
@IndexedEmbedded(depth = 1)
private EUser user;
@OneToMany(
fetch = FetchType.LAZY,
targetEntity = EDownload.class,
mappedBy = "document",
orphanRemoval = true,
cascade = CascadeType.ALL)
@IndexedEmbedded(depth = 1)
private Set<EDownload> downloads;
public EDocument() {
created = Calendar.getInstance();
}
// getters and setters
}
下载实体
@Entity
@Table(name = "downloads")
public class EDownload {
public static final String FIELD_REQUESTED = "requested";
@Id
@GeneratedValue
@Column(name = "id")
private Long id;
@Column(name = "requested")
@Field(name = FIELD_REQUESTED)
private Calendar requested;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "document_id", nullable = false)
private EDocument document;
public EDownload() {
requested = Calendar.getInstance();
}
// getters and setters
}
答案 0 :(得分:0)
我可能会使用@IndexedEmbedded
将匹配作为文档索引的一部分进行索引。然后,您针对description
字段运行查询,提供自定义Sort
实施。自定义排序将需要数据范围作为参数,然后计算此日期范围内的匹配并相应地进行排序。
答案 1 :(得分:0)
我最终得到的东西类似于@gmansoor建议的东西 - 第一个查询条款,返回ID,然后第二个查询基于这些ID。在Hibernate Search的单个查询中,没有一种方法可以做到这一点,所以这似乎是目前最好的解决方案。如果有人知道更好的方法,请告诉我。