从FullTextEntityManager获取QueryBuilder
FullTextEntityManager fullTextEntityManager
= Search.getFullTextEntityManager(entityManager);
QueryBuilder queryBuilder = fullTextEntityManager.getSearchFactory()
.buildQueryBuilder()
.forEntity(Product.class)
.get();
通过Hibernate query DSL创建Lucene查询:
org.apache.lucene.search.Query query = queryBuilder
.keyword()
.onField("productName")
.matching("iphone")
.createQuery();
包装Luncene查询至Hibernate查询
org.hibernate.search.jpa.FullTextQuery jpaQuery
= fullTextEntityManager.createFullTextQuery(query, Product.class);
执行查询:
List<Product> results = jpaQuery.getResultList();
Query keywordQuery = queryBuilder
.keyword()
.onField("productName")
.matching("iphone")
.createQuery();
keyword()指定搜索特定词,onField()告诉Lucene在哪里搜索,matching匹配需要搜索的关键词。
近似查询与关键词查询类似,只是可以定义一个“模糊”的限制,在这个限制内Lucene将接受两个术语为匹配结果。
通过ditdistanceupto(),可以定义术语之间的偏离程度。它可以设置为0、1和2,默认值为2(注意:这个限制来自Lucene的实现)。
通过withPrefixLength(),定义前缀的长度,这个长度是由模糊性所忽略的:
Query fuzzyQuery = queryBuilder
.keyword()
.fuzzy()
.withEditDistanceUpTo(2)
.withPrefixLength(0)
.onField("productName")
.matching("iPhaen")
.createQuery();
Hibernate Search也支持通配符查询,?号表示单个字符,*号表示任意字符:
Query wildcardQuery = queryBuilder
.keyword()
.wildcard()
.onField("productName")
.matching("Z*")
.createQuery();
如果想搜索多个词,可以使用短语搜索。使用phrase() 和 withSlop()方法,可以实现精确查询或近似句子。slop因子定义句子中允许其他词数量:
Query phraseQuery = queryBuilder
.phrase()
.withSlop(1)
.onField("description")
.sentence("with wireless charging")
.createQuery();
前面的查询方式都需要指定查询类型。使用简单查询字符串可以实现更强大的搜索功能,即实现运行时查询能力。其支持的查询类型如下:
下面示例综合了近似查询、词组查询以及布尔查询:
Query simpleQueryStringQuery = queryBuilder
.simpleQueryString()
.onFields("productName", "description")
.matching("Aple~2 + \"iPhone X\" + (256 | 128)")
.createQuery();
最后一个查询类型是同类词查询(More Like This)。提供一个实体,Hibernate Search 返回类似的实体列表,每个元素带有相似度评分。
前面已经提及,在模型属性上需要增加termVector = TermVector.YES,其告诉Lucene索引时存储每个词条的频率。
基于此,相似度将在查询执行时计算:
Query moreLikeThisQuery = queryBuilder
.moreLikeThis()
.comparingField("productName").boostedTo(10f)
.andField("description").boostedTo(1f)
.toEntity(entity)
.createQuery();
List<Object[]> results = (List<Object[]>) fullTextEntityManager
.createFullTextQuery(moreLikeThisQuery, Product.class)
.setProjection(ProjectionConstants.THIS, ProjectionConstants.SCORE)
.getResultList();
最后一个查询类型是同类词查询(More Like This)。提供一个实体,Hibernate Search 返回类似的实体列表,每个元素带有相似度评分。
前面已经提及,在模型属性上需要增加termVector = TermVector.YES,其告诉Lucene索引时存储每个词条的频率。
基于此,相似度将在查询执行时计算:
Query moreLikeThisQuery = queryBuilder
.moreLikeThis()
.comparingField("productName").boostedTo(10f)
.andField("description").boostedTo(1f)
.toEntity(entity)
.createQuery();
List<Object[]> results = (List<Object[]>) fullTextEntityManager
.createFullTextQuery(moreLikeThisQuery, Product.class)
.setProjection(ProjectionConstants.THIS, ProjectionConstants.SCORE)
.getResultList();
目前为止我们一直使用onField()方法在一个字段上执行查询,实际应用中也能基于多个字段:
Query luceneQuery = queryBuilder
.keyword()
.onFields("productName", "description")
.matching(text)
.createQuery();
而且,也可以针对每个字段分别搜索。如我们可以对不同字段定义不同的加权因子(boost):
Query moreLikeThisQuery = queryBuilder
.moreLikeThis()
.comparingField("productName").boostedTo(10f)
.andField("description").boostedTo(1f)
.toEntity(entity)
.createQuery();
最后Hibernate Search也支持使用不同策略实现组合查询:
SHOULD: 查询应该包括子查询匹配的元素
MUST: 查询必须包含子查询匹配的元素
MUST NOT: 查询不必包含子查询的元素
三者类似于布尔运算:and、or和not,但使用不同名称是为了强调它们也对相关性有影响。
举例:should在两个查询之间,只有有一个匹配则被返回,但如果两个都匹配,其相关性评分要高于只有一个匹配情况。
Query combinedQuery = queryBuilder
.bool()
.must(queryBuilder.keyword()
.onField("productName").matching("apple")
.createQuery())
.must(queryBuilder.range()
.onField("memory").from(64).to(256)
.createQuery())
.should(queryBuilder.phrase()
.onField("description").sentence("face id")
.createQuery())
.must(queryBuilder.keyword()
.onField("productName").matching("samsung")
.createQuery())
.not()
.createQuery();