Hibernate/Lucene是否可以在同一字段上进行排序和搜索?

4
我有一个已注释的类,我正在尝试对来自lucene/hibernate搜索查询的结果进行排序。我终于成功地让查询正常工作,但当我实施必要的注释(在jobStatus上)以对该列进行排序时,就无法搜索该列了。我是基于我在这里找到的指南。我一直在困惑如何处理整个hibernate搜索和排序的问题,现在我终于弄清楚如何进行排序和搜索,现在我需要能够同时进行它们。
@Entity
@Table(name="jobReq")
@Indexed
public class JobReq {

@Id
@DocumentId
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;

@Field(index = Index.YES)
@Column(name="jobId", nullable=false, unique=true)
private String jobId;

@Field(index = Index.YES)
@Column(name="jobTitle", nullable=false)
private String jobTitle;

@Field(index = Index.YES)
@Column(name="jobContract", nullable=false)
private String contract;

@Field(index = Index.YES)
@Column(name="jobProject", nullable=true)
private String project;

@Field(index = Index.YES)
@Column(name="jobLaborCategory", nullable=false)
private String laborCategory;

@Field(index = Index.YES)
@Column(name="jobSummary", nullable=false)
private String summary;

@Field(index = Index.YES)
@Column(name="jobDescription", nullable=false)
private String jobDescription;

@Fields({@Field, @Field(analyze  = Analyze.NO, name = "jobStatus")})
@Column(name="jobStatus", nullable=false)
private String status;

@Field(index = Index.YES)
@Column(name="TTONumber", nullable=false)
private String TTONumber;

@Field(index = Index.YES)
@Column(name="jobPostedDate", nullable=false)
@Type(type="date")
private Date postedDate;

还有来自搜索功能的片段

Field[] allFields = this.type.getDeclaredFields();
SortField field =new SortField(sortColumn, SortField.STRING, reverseSort);
Sort sort = new Sort(field);
hibQuery = fullTextSession.createFullTextQuery(bq, this.type).setSort(sort);
results = hibQuery.list();
3个回答

5
Hibernate Search文档提供了类似于Adam的解决方案来解决这个问题。您可以使用两个@Field注释,其中一个使用Analyze.NO进行排序,另一个使用Analyze.YES进行搜索,从而使字段被索引两次。请参考https://docs.jboss.org/hibernate/search/5.11/reference/en-US/html_single/#fields-annotation
@Entity
@Indexed(index = "Book")
public class Book {

    @Field
    @Field(name = "summary_forSort", analyze = Analyze.NO, store = Store.YES)
    @SortableField(forField = "summary_forSort")
    public String getSummary() {
        return summary;
    }

    // ...
}

分析: 确定属性是否被分析(Analyze.YES)或未分析(Analyze.NO)。默认值为Analyze.YES。

提示
您是否想要分析一个属性取决于您是希望按元素搜索,还是按包含的单词搜索。文本字段适合分析,但日期字段可能不适合。

提示
用于排序或聚合的字段不得进行分析。


3
原来你不能在同一字段上进行排序和搜索,那篇来自Hibernate书籍的文章有点误导人。所以我在Hibernate论坛上找到了解决方案,即创建一个“影子”列,其中一个被注释为搜索,而另一个被注释为排序。
我花了一段时间才找到这个解决方案,主要是因为答案似乎有点“hack-y”,但相当直接和简单,数据复制始终是我的训练中的禁忌。但话说回来,我想你每天都会学到新东西。

1

两件事:

  1. 在每个列上创建索引可能会影响性能,因为索引更新不是免费的。这也会使用过多的额外存储空间。当然,如果这实际上不是你的瓶颈,那就无所谓了。

  2. 您可以使用Hibernate Criteria进行排序,例如:

    Criteria c = session.createCriteria(MyObject.class).addOrder(Order.desc(sortColumn));
    Query q = session.createFullTextQuery(bq).setCriteriaQuery(c);
    

    排序键列不需要被索引。


太棒了,谢谢。我有两个问题,实际上我还有其他字段(不想列出所有不必要的字段),所以如果我不对它们进行排序或搜索,最好不要对它们进行索引吗?另外,如果我想使用自定义排序标准(例如,将“打开”排在“关闭”之前),我可以使用这种方法吗? - Adam James
我刚刚尝试了这种方法,我删除了@Fields({@Field, @Field(analyze = Analyze.NO, name = "jobStatus")})并用@Field()替换它,然后尝试根据列“jobStatus”和“status”对其进行排序。但是它没有排序,我不确定这是因为变量名为“status”,而数据库中的列名为“jobStatus”。 - Adam James
我必须道歉并停止在这里回答,因为我对Hibernate Search不是100%熟悉,我认为我只会给你提供错误信息。我没有意识到Search使用自己的索引方案。因此,上面我所说的第1点无效。我指的是数据库级别的索引。在研究Hibernate Search时,似乎需要告诉Search索引哪些字段,并且Search使用自己的索引格式。我可能也错了,但是我不建议遵循我以前关于索引的建议。很抱歉让您走上错误的道路。 - Jason C
话虽如此,仍然有这一点是成立的,并且回答了你上面提出的问题,那就是如果你不在字段上进行搜索/排序,那么不,你不应该在其上创建索引-你会牺牲性能来生成没有任何收益的索引,因为你从未使用它们。如果你改变可搜索的字段,你总是可以之后添加索引。这个论点中不成立的部分是,如果你想要搜索/排序,你必须创建一个索引。 - Jason C
不,你不能使用Hibernate Criteria实现这样的自定义搜索条件。Criteria排序仅限于使用SQL ORDER BY可以做的内容。Criteria系统基本上为您提供了一种干净的方式来以编程方式构建HQL查询(而不是显式地构建查询字符串)。对于基于业务值的排序,您将不得不在业务逻辑中进行排序,通过使用自定义的“比较器”对对象集合进行排序。或者,如果更适合您,您可以分别选择“打开”和“关闭”的项目,并将两个列表连接起来。 - Jason C
好的,回到起点了哈哈,但是感谢你提供关于不需要索引的信息。这是我基本上知道的事情,但我没有想到需要指定(默认为索引)。 - Adam James

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接