2014-12-02 53 views
0

我有两个对象 - 一个Document对象和Hit对象:Hibernate Search的排序采集日期范围内的数

Document 
    id 
    description 
    hits (Collection of type Hits) 
    ... 

Hit 
    documentId (Type Document) 
    date 
    ... 

我试图创建一个Hibernate搜索查询,以搜索文档描述,然后按给定日期范围内的点击次数对结果进行排序。

我有一点麻烦缠绕我的头围绕如何做到这一点。我查看了this,但它考虑了点击总数,并且不允许动态日期范围查询,因为桥接字段是独立于日期更新的。

目前,我有我的Document对象的索引与description工作正常搜索。我想我可能需要创建一个指数为Hit对象,通过documentId对其运行查询的日期范围,组,然后运行使用抗Document索引搜索项的第二个查询。

鉴于这种策略,我仍然不知道如何:

  1. 组由documentId
  2. 命中保持结果的顺序从匹配查询
  3. 手柄分页。

我的猜测是,我需要得到来自Hits指数所有结果(使用某种类型的刻面逻辑的分组/排序,也许?),再搭配上documentId /学期,并在第二个查询处理分页。我只是不确定在使用QueryBuilder接口来构建查询时,所有这些都看起来如何,或者如果有一种完全不同的方式来处理这个问题,我还没有想到。

UPDATE

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

除非您对Hit的搜索可以更改文档的返回数量,否则我会在hibernate中使用第二个查询来按命中次数获得排序。因此,您搜索描述并获取文档ID列表(投影),然后执行第二个查询(native或hql)传递文档ID? Lucene/Hibernate搜索适用于文本的布尔搜索,但不适合您的第二个特定场景。 – gmansoor 2014-12-05 05:16:13

回答

0

我结束了类似于@gmansoor建议一些事情 - 针对相应的条款第一个查询,返回的ID,然后根据这些ID的第二个查询。在Hibernate Search的单个查询中似乎没有办法做到这一点,所以这似乎是目前最好的解决方案。如果有人知道更好的方法来做到这一点,请让我知道。

0

我可能会使用@IndexedEmbedded作为文档索引的一部分将索引编入索引。然后,对description字段运行查询,提供自定义Sort实现。自定义排序将需要数据范围作为参数,然后对此日期范围内的匹配进行计数并相应地进行排序。

+0

感谢您的回复。你介意给我一些关于创建自定义排序的文档的方向吗?我的搜索没有发现任何东西。 – Luke 2014-12-02 21:27:12

+0

签出章节5.1.3.3关于应用排序 - http://docs.jboss.org/hibernate/stable/search/reference/en-US/html_single/#d0e5655并查看源代码中的SortTest,它使用自定义SumFieldComparatorSource - http://docs.jboss.org/hibernate/stable/search/reference/en-US/html_single/#d0e5655 – Hardy 2014-12-03 11:23:38

+0

也许我有点密集,但我仍然不确定如何应用此对我的特殊情况。看起来你引用的[SortTest](https://github.com/hibernate/hibernate-search/blob/b8c78df7403f42ab3f8f73603b01a944cab0a47d/orm/src/test/java/org/hibernate/search/test/query/SortTest.java)对'NumberHolder'类的属性进行操作,在那里我将使用'Hit'类中需要出现的日期范围。另外,如果排除在范围之外的“命中”会被排除在外? (这将有一个0计数)。或者这需要在这种情况之外发生? – Luke 2014-12-03 15:07:50