我有一个与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);
...