首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件架构设计 >

Hibernate Search(基于version3.4)-第五章Querying

2012-11-06 
Hibernate Search(基于version3.4)--第五章QueryingQuerying?Hibernate Search的第二个很重要的能力是运行

Hibernate Search(基于version3.4)--第五章Querying

Querying

?

Hibernate Search的第二个很重要的能力是运行Lucene queries并通过Hibernate session获得受管理的实体。search在提供了Lucene强大的功能之外还保持着Hibernate的编程模式(给Hibernate典型的search机制提供另外的dimension:HQL,Criteria query,native SQL query)

?

预备和运行一个query由4个步骤组成:

?

创建一个FullTextSession通过Hibernate Search query DSL(推荐的)或Lucene query API创建一个Lucene query。使用org.hibernate.Query包装Lucene query通过调用list() 或scroll()执行search

你必须使用FullTextSession来访问query功能。这个具体的search session包装了一个一般的org.hibernate.Session来提供query和indexing能力。

?

Example 5.1. Creating a FullTextSession

?

?

?

Note:建立在Lucene query之上的Hibernate query是一般的org.hibernate.Query实现,这意味着你可以使用与其他Hibernate query功能(HQL,Native or Criteria)相同的模式来编程。org.hibernate.Query中的list(),uniqueResult(),iterate()和scroll()方法都可以使用。

?

你也可以使用Hibernate的Java Persistence API:

?

Example 5.3. Creating a Search query using the JPA API

?

?5.1.2.7. 查询选项(Query options)我们在前面的例子中看到过不少的查询选项,但让我们再一次总结这些选项:boostedTo (on query type and on field): 使用给定的factor来boost整个query或指定的fieldwithConstantScore (on query):所有匹配query的结果都有一个常量的分数等同于boost。filteredBy(Filter)?(on query):使用Filter实例来过滤查询结果ignoreAnalyzer (on field):不用analyzer来处理这个field。ignoreFieldBridge (on field):不用field bridge来处理这个field。

?

让我们看看应用了这些选项的例子:

?

?

Hibernate Search从Lucene index中抽离出实体对象的属性并把它们向上转换成Object,最终结果返回Object[]列表。Projection避开了潜在数据库的查询(如果响应时间很重要的话,这就会很有用了)。然而,它还有一些约束条件:

?

?

投影所对应的属性必须保存在index中,即@Field(store=Store.YES)属性投影必须使用org.hibernate.search.bridge.TwoWayFieldBridge或org.hibernate.search.bridge.TwoWayStringBridge的FieldBridge实现,后者是一个简便版本。

?

?

Note:所有Hibernate Search内建类型都是two-way的。

?

你只可以投影实体对象或其关联对象中的简单属性。意思是说不能投影内嵌的整个实体。投影不能应用于使用了@IndexedEmbedded的集合或map。Projection还有另外的用途。Lucene能为结果集提供一些元信息。通过使用指定的projection常量,projection机制能获取这样的元信息:

?

?

?

Example 5.10. Using projection in order to retrieve meta data

?

?

?

?

?

你可以混合投影field和projection常量。下面列举了可用的projection常量:

?

FullTextQuery.THIS:返回整个受管对象(这不再是使用projected query)FullTextQuery.DOCUMENT:返回实体对象对应的Lucene Document。FullTextQuery.OBJECT_CLASS:返回实体对象的class。FullTextQuery.SCORE:返回对应的document scoreFullTextQuery.ID:投影对象的id值。FullTextQuery.DOCUMENT_ID:投影Lucene document id。小心,Lucene document id会在打开新的IndexReader时变得不一样。(这个功能还在测试中)FullTextQuery.EXPLANATION:返回匹配的Lucene Explanation对象。

?

?

?

?

?

5.1.3.6.自定义对象初始化策略(Customizing object initialization strategies)

?

?

?

?

默认地,Hibernate Search使用最合适的策略来初始化匹配的实体对象。它运行一个或多个查询来获取请求的实体对象。当实体对象存储在持久化上下文或二级缓存中时,默认的方法会最小程度地访问数据库,因此也是最好的方法。

?

如果大多数的实体对象缓存在二级缓存中,你可以强迫Hibernate Search先从缓存中获取对象,如果没有再访问数据库。

?

Example 5.11. Check the second-level cache before using a query

?

?

?

?

ResultTransformer的实现例子可以在Hibernate Core codebase中找到。

?

?

5.2.4. Understanding results

有时候你可能会因为某些查询结果而感到迷惑。Luke是一个很好的工具帮助你了解查询的结果。然而,Hibernate Search也能让你从给定的query中访问Lucene Explanation对象。这个对象对于Lucene用户来说是相当高级的,不过能为理解一个结果的分数提供很好的帮助。你有两种方式来访问结果对应的Explanation对象:

?

使用fullTextQuery.explain(int)方法使用projection第一种方法用document id作为参数来返回Explanation对象。document id可以通过projection和FullTextQuery.DOCUMENT_ID常量获取。

?

?

?

Warning:document id与实体的id是不同的。不要混淆这两个概念。

?

?

第二种方法让你使用FullTextQuery.EXPLANATION常量来投影Explanation对象。

?

Example 5.18. Retrieving the Lucene Explanation object using projection

?

?

?在这个例子中,我们在query之上使用了两个filter。如果你有这个需要的话,你可以使用任意数量的filter。

?

声明filter是通过@FullTextFilterDef注解完成。该注解标注在带有@Indexed注解的实体上。这暗示了filter声明是全局的和它们的名字必须是唯一的。如果两个不同的@FullTextFilterDef声明两个相同名字的filter,就会抛出SearchException。每个命名的filter必须指定它自己的filter实现。

?

Example 5.20. Defining and implementing a Filter

?

?

BestDriversFilter是一个简单的Lucene filter实现,它把所有'score'不为5的结果过滤掉了。在这个例子中,具体的filter直接实现了org.apache.lucene.search.Filter并包含一个无参的构造器。

?

如果你的Filter创建需要额外的步骤或Filter需要使用有参数的构造器,那么你就要使用factory模式:

?

Example 5.21. Creating a filter using the factory pattern

?

?

?

当运行这个faceting request,将会为每个离散值(在这里是'label' field的值)创建一个Facet实例。Facet实例会记录下实际的field value,包括这个field value的值在原查询结果中出现的频率。orderedBy,includeZeroCounts和maxFacetCount是任何faceting request的可选参数。orderedBy允许指定返回的facet的顺序,默认是FacetSortOrder.COUNT_DESC,不过你也可能按field value或按指定的范围排序。includeZeroCount定义是否计数为0的facet也包含在结果中(默认是包括的)。maxFacetCount限制了最大的facet返回数。

?

?

?

Tip:应用faceting的indexed field需要满足一些先决条件。被索引的属性域必须是字符串,日期或数值类型。另外属性域必须以Index.UN_TOKENIZED方式索引,数值型的属性域必须标注为@NumericField

?

?

?

range faceting request的创建非常相似,除了我们必须为field指定一个范围值。Example 5.27,“Creating a range faceting request”是一个range faceting request的例子,它指定了三个不同的price范围。below和above只能指定一次,但你可以任意地指定from-to范围。通过excludeLimit方法定义是否包括每个范围的边界。

?

?

Example 5.27. Creating a range faceting request

?

?

?

?

5.4.2. Applying a faceting request

在5.4.1节'creating a faceting request',我们已经看到怎么样去创建一个faceting request。现在是时候在查询时应用这个faceting request。关键在于从FulltextQuery中获取的FacetManager。(see Example 5.28, “Applying a faceting request”)

?

Example 5.28. Applying a faceting request

?

?

?

只要你有这样的需要,你可以使用添加任何数量的faceting request,并通过getFacets()和faceting request name来获取Facet。同样地,有一个disableFaceting()方法,它可以通过request name来禁用一个faceting request。

?

5.4.3. 限制查询结果(Restricting query results)

?

最后但不重要的是,你可以应用任何返回的Facet作为你原本的query的额外的criteria,这样就可以实现一个"drill-down"功能。为了这个目的,就得利用FacetSelection这个类。可以通过FacetManager来应用FacetSelection,并允许你选择一个facet作为query criteria(selectFacet),移除一个facet restriction(deselectFacets),移除所有facet restrictions(clearSelectedFacets)并获取当前所有的selected facets(getSelectedFacets)。?Example 5.29, “Restricting query results via the application of a?FacetSelection” shows an example.

?

?

Example 5.29. Restricting query results via the application of a FacetSelection

?

?

5.5. Optimizing the query process

查询性能依赖于下面几个准则:

?

Lucene query自身的问题。查看关于这方面更多的文献加载对象的数量。使用pagination或index projection。Hibernate Search与Lucene reader的交互方式:定义合适的Reader strategy。缓存频繁使用的从index中抽离的值。see Section 5.5.1, “Caching index values:FieldCache”

?

5.5.1. Caching index values: FieldCache

Lucene index的主要功能是鉴定与查询的匹配关系,然而查询完成后,必须分析结果并抽离有用的信息:典型地,Hibernate Search需要抽出Class type和primary key。

?

从index中抽离需要的值是一种性能消耗,这种消耗可能很低并不易让人知道,但在某些时候caching会是一种很好的实践。

?

缓存的精确需要依赖于使用Projection的类型(see Section 5.1.3.5,“Projection”),有些时候,Class type是不需要缓存的,因为它可以通过query上下文获知。

?

使用@CacheFromIndex注解,你可以试验缓存Hibernate Search所需要的不同的主元数据field。

?

import static org.hibernate.search.annotations.FieldCacheType.CLASS;import static org.hibernate.search.annotations.FieldCacheType.ID;@Indexed@CacheFromIndex( { CLASS, ID } )public class Essay {    ...

?

?

通过这个注解现在就可以缓存Class type和ID。

CLASS:Hibernate Search将会使用Lucene的FieldCache来改善从index抽离Class type的性能。默认下这个值是可用的,Hibernate Search将应该这个值如果你没有指定@CacheFromIndex注解。ID:缓存主键标识符。这好像能提供最好的查询表现,但同时也会消耗更多的内存(有可能会降低性能)

Note:在warmup(运行一些query)后,测量性能和内存消耗之间的影响:使用Field Cache好像能改善性能,但并不总是这样的。

?

?

使用FieldCache有两个缺点:

内存使用:缓存会消耗大量的内存。典型的CLASS缓存比ID缓存要求更低。Index warmup:当使用了field cache,第一次查询会比不用缓存慢。对于某些查询,classtype并不是必需的,在某些时候,即使你使用了CLASS field cache,它可能并不会被使用;例如如果你查询单个class,显然地返回的值将会是这个class类型。
对于使用ID FieldCache,实体的id必须使用TwoWayFieldBridge(比如所有内建的bridge),and all types being loaded in a specific query must use the fieldname for

the id, and have ids of the same type (this is evaluated at each Query execution).

?

?

?

?

?

热点排行