Hibernate Search / Lucene-用单个查询搜索并排名无关的实体



我有一个与Hibernate Search和Lucene一起使用的全文搜索,因为我可以成功地搜索特定字段的给定模型实体。

但是,我不是一次搜索一种类型的实体,而是要实现"通用"搜索,同时搜索不同的实体类型,将搜索短语与每个不同实体类型的适当字段匹配,并且然后以与搜索词相关的相关性来对结果进行排名,而与实体类型无关。

因此,假设我有不同的实体,foo和bar

@Entity
@Indexed
@AnalyzerDef(
  name="fulltext",
  tokenizer=@TokenizerDef(factory=StandardTokenizerFactory.class),
  filters={
    @TokenFilterDef(factory=LowerCaseFilterFactory.class),
    @TokenFilterDef(factory=SnowballPorterFilterFactory.class, 
      params={@Parameter(name="language", value="English") })
  }
)
public class Foo {
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Integer fooId;
  @Column
  @Field 
  @Analyzer(definition="fulltext") 
  private String fieldA;
  ...

@Entity
@Indexed
public class Bar {
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Integer barId;
  @Column
  @Field 
  @Analyzer(definition="fulltext") 
  private String fieldB;
  @Column
  @Field 
  @Analyzer(definition="fulltext") 
  private String fieldC;
  ...

所以我想搜索"一些文本"并通过foo.fielda和bar.fieldb和/或bar.fieldc

匹配

我正在使用的当前搜索类型是特定于特定实体的,例如:

fullTextSession = Search.getFullTextSession(hibernateSession);
Query query = fullTextSession.createFullTextQuery(
                fullTextSession
                  .getSearchFactory()
                  .buildQueryBuilder()
                  .forEntity(Foo.class)
                  .get()
                  .keyword()
                  .onFields("fieldA")
                  .matching("some text")
                  .createQuery(),
              Foo.class);
 query.list() // gets ranked list of Foo entities matching "some text"

显然,上述Lucene查询是FOO实体的特定于Foo。

那么,是否可以修改Lucene查询以还包括栏结果,在bar.fieldb和bar.fieldc fields上匹配?

我知道fullTextSession.createFullTextQuery(fulltextSession, Class...)方法也会接受bar.class,返回bar结果,但我不知道如何修改实际查询以首先在bar实体上进行搜索。


我正在考虑解决此问题的另一种方式是进行单独的查询,一个用于FOO实体,一个用于bar实体,然后合并两个结果集并通过"匹配相关性得分"对它们进行排序 - 但是我可以't查找如何获得结果的得分!

编辑上述方法可能不起作用 - 事实证明,您可以通过预测获得结果的分数,但是从单独查询中得分的文档则不能有意义地比较:

fullTextQuery.Score:返回查询中的文档分数。分数很方便地将一个结果与一个给定查询的另一个结果进行比较,但是在比较不同查询的结果时毫无用处。


很抱歉,如果我在这里涵盖了良好的地面,但是我一直在错误的地方搜索几个小时,并且找不到任何有用的文档,这令人沮丧,因为我想这是令人沮丧的Lucene的相当常见用例。

您可以编写两个查询,并使用Occur.SHOULD通过BooleanQuery组合它们。然后使用createFullTextQuery(booleanQuery, Foo.class, Bar.class);搜索两种类型的实体。

受Hardy答案的启发,我使用了一个带有两个条款的布尔值,这两种都会发生。这导致查询的所需行为。

这是代码:

...
fullTextSession = Search.getFullTextSession(hibernateSession);
String searchPhrase = "some text";
org.apache.lucene.search.Query fooQuery =
  fullTextSession
    .getSearchFactory()
    .buildQueryBuilder()
    .forEntity(Foo.class)
    .get()
    .keyword()
    .onFields("fieldA")
    .matching(searchPhrase)
    .createQuery();
org.apache.lucene.search.Query barQuery =
  fullTextSession
    .getSearchFactory()
    .buildQueryBuilder()
    .forEntity(Bar.class)
    .get()
    .keyword()
    .onFields("fieldB", "fieldC")
    .matching(searchPhrase)
    .createQuery();
BooleanQuery query = new BooleanQuery();
query.add(new BooleanClause(fooQuery, BooleanClause.Occur.SHOULD));
query.add(new BooleanClause(barQuery, BooleanClause.Occur.SHOULD));
Query hibernateQuery = 
        fullTextSession.createFullTextQuery(query, Foo.class, Bar.class);
...

最新更新