Author: epbernard
Date: 2007-05-30 22:48:08 -0400 (Wed, 30 May 2007)
New Revision: 11600
Modified:
trunk/HibernateExt/search/doc/reference/en/master.xml
trunk/HibernateExt/search/doc/reference/en/modules/architecture.xml
trunk/HibernateExt/search/doc/reference/en/modules/configuration.xml
trunk/HibernateExt/search/doc/reference/en/modules/mapping.xml
trunk/HibernateExt/search/doc/reference/en/modules/query.xml
trunk/HibernateExt/search/src/java/org/hibernate/search/reader/ReaderProvider.java
Log:
HSEARCH-39
HSEARCH-38
Update search documentation
Modified: trunk/HibernateExt/search/doc/reference/en/master.xml
===================================================================
--- trunk/HibernateExt/search/doc/reference/en/master.xml 2007-05-30 20:25:23 UTC (rev
11599)
+++ trunk/HibernateExt/search/doc/reference/en/master.xml 2007-05-31 02:48:08 UTC (rev
11600)
@@ -1,25 +1,25 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
+<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3CR3//EN"
-
"../../../../../Hibernate3/doc/reference/support/docbook-dtd/docbookx.dtd" [
- <!ENTITY architecture SYSTEM "modules/architecture.xml">
- <!ENTITY configuration SYSTEM "modules/configuration.xml">
- <!ENTITY mapping SYSTEM "modules/mapping.xml">
- <!ENTITY query SYSTEM "modules/query.xml">
- <!ENTITY batchindex SYSTEM "modules/batchindex.xml">
- ]>
+"../../../../../Hibernate3/doc/reference/support/docbook-dtd/docbookx.dtd" [
+<!ENTITY architecture SYSTEM "modules/architecture.xml">
+<!ENTITY configuration SYSTEM "modules/configuration.xml">
+<!ENTITY mapping SYSTEM "modules/mapping.xml">
+<!ENTITY query SYSTEM "modules/query.xml">
+<!ENTITY batchindex SYSTEM "modules/batchindex.xml">
+]>
<book lang="en">
<bookinfo>
<title>Hibernate Search</title>
- <subtitle>Apache <trademark>Lucene</trademark>
- Integration</subtitle>
+ <subtitle>Apache <trademark>Lucene</trademark>
Integration</subtitle>
+
<subtitle>Reference Guide</subtitle>
- <releaseinfo>3.0.0.Beta1</releaseinfo>
+ <releaseinfo>3.0.0.Beta2</releaseinfo>
<mediaobject>
<imageobject>
- <imagedata fileref="images/hibernate_logo_a.png"
format="png"/>
+ <imagedata fileref="images/hibernate_logo_a.png"
format="png" />
</imageobject>
</mediaobject>
</bookinfo>
@@ -29,29 +29,29 @@
<preface id="preface" revision="2">
<title>Preface</title>
- <para>Full text search engines like <productname>Apache
Lucene</productname>
- are a very powerful technology to
-bring free text/efficient queries to applications. If suffers several mismatches
-when dealing with a object domain model (keeping the index up to date, mismatch
-between the index structure and the domain model, querying mismatch...)
-Hibernate Search indexes your domain model thanks to a few annotations, takes
-care of the database / index synchronization and brings you back regular managed
-objects from free text queries.
-Hibernate Search is using <ulink url="http://lucene.apache.org">Apache
Lucene</ulink>
-under the cover.</para>
+ <para>Full text search engines like <productname>Apache
+ Lucene</productname> are a very powerful technology to bring free
+ text/efficient queries to applications. If suffers several mismatches when
+ dealing with a object domain model (keeping the index up to date, mismatch
+ between the index structure and the domain model, querying mismatch...)
+ Hibernate Search indexes your domain model thanks to a few annotations,
+ takes care of the database / index synchronization and brings you back
+ regular managed objects from free text queries. Hibernate Search is using
+ <ulink url="http://lucene.apache.org">Apache Lucene</ulink>
under the
+ cover.</para>
- <para>Hibernate Search is a work in progress and new features are cooking in
- this area. So expect some compatibility changes in subsequent
- versions.</para>
+ <para>Hibernate Search is a work in progress and new features are cooking
+ in this area. So expect some compatibility changes in subsequent
+ versions.</para>
</preface>
- &architecture;
+ &architecture;
- &configuration;
+ &configuration;
- &mapping;
+ &mapping;
- &query;
+ &query;
- &batchindex;
+ &batchindex;
</book>
\ No newline at end of file
Modified: trunk/HibernateExt/search/doc/reference/en/modules/architecture.xml
===================================================================
--- trunk/HibernateExt/search/doc/reference/en/modules/architecture.xml 2007-05-30
20:25:23 UTC (rev 11599)
+++ trunk/HibernateExt/search/doc/reference/en/modules/architecture.xml 2007-05-31
02:48:08 UTC (rev 11600)
@@ -6,31 +6,29 @@
engine. Both are backed by Apache Lucene.</para>
<para>When an entity is inserted, updated or removed to/from the database,
- Hibernate Search keeps track of this event
- (through the Hibernate event system) and schedule an index update. All the
- index updates are handled for you without you having to use the Apache
- Lucene APIs.</para>
+ Hibernate Search keeps track of this event (through the Hibernate event
+ system) and schedule an index update. All the index updates are handled for
+ you without you having to use the Apache Lucene APIs.</para>
<para>To interact with Apache Lucene indexes, Hibernate Search has the
notion of <classname>DirectoryProvider</classname> . A directory provider
will manage a given Lucene <classname>Directory</classname> type. You can
configure directory providers to adjust the directory target.</para>
- <para>Hibernate Search can also use a Lucene
- index to search an entity and return a (list of) managed entity saving you
- from the tedious Object / Lucene Document mapping and low level Lucene APIs.
- The same persistence context is shared between Hibernate and Hibernate
- Search ; as a matter of fact, the Seearch Session is built on top of the
- Hibernate Session. The application code use the unified
- <classname>org.hibernate.Query</classname> API exactly the way a HQL or
- native query would be done.</para>
+ <para>Hibernate Search can also use a Lucene index to search an entity and
+ return a (list of) managed entity saving you from the tedious Object /
+ Lucene Document mapping and low level Lucene APIs. The same persistence
+ context is shared between Hibernate and Hibernate Search ; as a matter of
+ fact, the Search Session is built on top of the Hibernate Session. The
+ application code use the unified
<classname>org.hibernate.Query</classname>
+ API exactly the way a HQL or native query would be done.</para>
<section>
<title>Batching Scope</title>
- <para>To be more efficient, Hibernate Search batch the interactions with
- the Lucene index. There is currently two types of batching depending on
- the expected scope.</para>
+ <para>To be more efficient, Hibernate Search batch the write interactions
+ with the Lucene index. There is currently two types of batching depending
+ on the expected scope.</para>
<para>When out of transaction, the index update operation is executed
right after the actual database operation. This scope is really a no
@@ -55,9 +53,9 @@
the transaction is committed.</para>
<note>
- <para>Disclamer, the work in not ACID in the strict sense of it, but
- ACID behavior is rarely useful for full text search indexes since
- they can be rebuilt from the source at any time.</para>
+ <para>Disclaimer, the work in not ACID in the strict sense of it,
+ but ACID behavior is rarely useful for full text search indexes
+ since they can be rebuilt from the source at any time.</para>
</note>
</listitem>
</itemizedlist>
@@ -80,7 +78,7 @@
<para>Hibernate Search offers the ability to let the scoped work being
processed by different back ends. Two back ends are provided out of the
- box for 2 different scenarii.</para>
+ box for 2 different scenarios.</para>
<section>
<title>Lucene</title>
@@ -146,8 +144,8 @@
<title>Custom</title>
<para>Hibernate Search is an extensible architecture. While not yet part
- of the public API, pluging a third party back end is possible. Feel free
- to drop ideas to
+ of the public API, plugging a third party back end is possible. Feel
+ free to drop ideas to
<literal>hibernate-dev(a)lists.jboss.org</literal>.</para>
</section>
</section>
@@ -185,4 +183,44 @@
completely unrealistic way).</para>
</section>
</section>
+
+ <section id="search-architecture-readerstrategy" xreflabel="Reader
strategy">
+ <title>Reader strategy</title>
+
+ <para>When executing a query, Hibernate Search interacts with the Apache
+ Lucene indexes through a reader strategy.</para>
+
+ <section>
+ <title>not-shared</title>
+
+ <para>Every time a query is executed, a Lucene IndexReader is opened.
+ This strategy is not the most efficient, opening and warming up an
+ IndexReader can be a relatively expensive operation. This strategy is
+ the default, but will be changed in the future.</para>
+ </section>
+
+ <section>
+ <title>shared</title>
+
+ <para>Hibernate Search will share the same IndexReader for a given index
+ provided that the IndexReader is still up-to-date. Generally speaking,
+ this strategy provides much better performance than the previous one. It
+ is especially true if the number of updates is much lower than the
+ read.</para>
+ </section>
+
+ <section>
+ <title>custom</title>
+
+ <para>You can write your own reader strategy that suits your application
+ needs by implementing
+ <classname>org.hibernate.search.reader.ReaderProvider</classname>. The
+ implementation must be thread safe.</para>
+
+ <note>
+ <para>Some additional strategies are planned in future versions of
+ Hibernate Search</para>
+ </note>
+ </section>
+ </section>
</chapter>
\ No newline at end of file
Modified: trunk/HibernateExt/search/doc/reference/en/modules/configuration.xml
===================================================================
--- trunk/HibernateExt/search/doc/reference/en/modules/configuration.xml 2007-05-30
20:25:23 UTC (rev 11599)
+++ trunk/HibernateExt/search/doc/reference/en/modules/configuration.xml 2007-05-31
02:48:08 UTC (rev 11600)
@@ -351,6 +351,26 @@
</section>
</section>
+ <section>
+ <title>Reader strategy configuration</title>
+
+ <para>The different reader strategies are described in <xref
+ linkend="search-architecture-readerstrategy" /> .The default reader
+ strategy is <literal>not-shared</literal>. This can be
adjusted:</para>
+
+ <programlisting>hibernate.search.reader.strategy =
shared</programlisting>
+
+ <para>Adding this property switch to the <literal>shared</literal>
+ strategy.</para>
+
+ <para>Or if you have a custom reader strategy:</para>
+
+ <programlisting>hibernate.search.reader.strategy =
my.corp.myapp.CustomReaderProvider</programlisting>
+
+ <para>where
<classname>my.corp.myapp.CustomReaderProvider</classname> is
+ the custom strategy implementation</para>
+ </section>
+
<section id="search-configuration-event" revision="2">
<title>Enabling automatic indexing</title>
@@ -367,18 +387,20 @@
configuration is not useful with Hibernate Annotations or Hibernate
EntityManager.</para>
- <programlisting><session-factory>
- ...
- <event type="post-update"
- <listener
class="org.hibernate.search.event.FullTextIndexEventListener"/>
- </event>
- <event type="post-insert"
- <listener
class="org.hibernate.search.event.FullTextIndexEventListener"/>
- </event>
- <event type="post-delete"
- <listener
class="org.hibernate.search.event.FullTextIndexEventListener"/>
- </event>
-</session-factory></programlisting>
+ <programlisting><hibernate-configuration>
+ <session-factory>
+ ...
+ <event type="post-update"
+ <listener
class="org.hibernate.search.event.FullTextIndexEventListener"/>
+ </event>
+ <event type="post-insert"
+ <listener
class="org.hibernate.search.event.FullTextIndexEventListener"/>
+ </event>
+ <event type="post-delete"
+ <listener
class="org.hibernate.search.event.FullTextIndexEventListener"/>
+ </event>
+ </session-factory>
+</hibernate-configuration></programlisting>
<para>Be sure to add the appropriate jar files in your classpath. Check
<literal>lib/README.TXT</literal> for the list of third party libraries.
A
Modified: trunk/HibernateExt/search/doc/reference/en/modules/mapping.xml
===================================================================
--- trunk/HibernateExt/search/doc/reference/en/modules/mapping.xml 2007-05-30 20:25:23 UTC
(rev 11599)
+++ trunk/HibernateExt/search/doc/reference/en/modules/mapping.xml 2007-05-31 02:48:08 UTC
(rev 11600)
@@ -49,13 +49,14 @@
<listitem>
<para><literal>store</literal> : describe whether or not the
property is stored in the Lucene index. You can store the value
- <literal>Store.YES</literal> (comsuming more space in the index),
- store it in a compressed way <literal>Store.COMPRESS</literal>
(this
- does consume more CPU), or avoid any storage
- <literal>Store.NO</literal> (this is the default value). When a
- property is stored, you can retrieve it from the Lucene Document
- (note that this is not related to whether the element is indexed or
- not).</para>
+ <literal>Store.YES</literal> (comsuming more space in the index
but
+ allowing projection, see <xref linkend="search-query" /> for
more
+ information), store it in a compressed way
+ <literal>Store.COMPRESS</literal> (this does consume more CPU), or
+ avoid any storage <literal>Store.NO</literal> (this is the default
+ value). When a property is stored, you can retrieve it from the
+ Lucene Document (note that this is not related to whether the
+ element is indexed or not).</para>
</listitem>
<listitem>
@@ -74,18 +75,22 @@
annotation.</para>
<para>Whether or not you want to store the data depends on how you wish
- to use the index query result. As of today, for a pure
- Hibernate Search usage, storing is not
- necessary. Whether or not you want to tokenize a property or not depends
- on whether you wish to search the element as is, or only normalized part
- of it. It make sense to tokenize a text field, but it does not to do it
- for a date field (or an id field).</para>
+ to use the index query result. For a regular Hibernate Search usage,
+ storing is not necessary. However you might want to store some fields to
+ subsequently project them (see <xref linkend="search-query" /> for
more
+ information). </para>
+ <para>Whether or not you want to tokenize a property depends on whether
+ you wish to search the element as is, or by the words it contains. It
+ make sense to tokenize a text field, but it does not to do it for a date
+ field (or an id field). Note that fields used for sorting must not be
+ tokenized.</para>
+
<para>Finally, the id property of an entity is a special property used
- by Hibernate Search to ensure index unicity
- of a given entity. By design, an id has to be stored and must not be
- tokenized. To mark a property as index id, use the
- <literal>@DocumentId</literal> annotation.</para>
+ by Hibernate Search to ensure index unicity of a given entity. By
+ design, an id has to be stored and must not be tokenized. To mark a
+ property as index id, use the <literal>@DocumentId</literal>
+ annotation.</para>
<programlisting>@Entity
@Indexed(index="indexes/essays")
@@ -153,6 +158,58 @@
@Field(index=Index.TOKENIZED)
private String city;
+ <emphasis role="bold">@ContainedIn</emphasis>
+ @OneToMany(mappedBy="address")
+ private Set<Place> places;
+ ...
+}</programlisting>
+
+ <para>In this example, the place fields will be indexed in the
+ <literal>Place</literal> index. The
<literal>Place</literal> index
+ documents will also contain the fields <literal>address.id</literal>,
+ <literal>address.street</literal>, and
<literal>address.city</literal>
+ which you will be able to query from. This is done thanks to the
+ <literal>@IndexedEmbedded</literal> annotation.</para>
+
+ <para><literal>@ContainedIn</literal> is useful on embedded
objects that
+ are also entities (like <literal>Address</literal> in the example): it
+ basically means that when an address entity is updated, the index
+ document of the associated <literal>Place</literal>(s), also have to
be
+ updated.</para>
+
+ <para>Let's make our example a bit more complex:</para>
+
+ <programlisting>@Entity
+@Indexed
+public class Place {
+ @Id
+ @GeneratedValue
+ @DocumentId
+ private Long id;
+
+ @Field( index = Index.TOKENIZED )
+ private String name;
+
+ @OneToOne( cascade = { CascadeType.PERSIST, CascadeType.REMOVE } )
+ <emphasis role="bold">@IndexedEmbedded</emphasis>
+ private Address address;
+ ....
+}
+
+@Entity
+@Indexed
+public class Address {
+ @Id
+ @GeneratedValue
+ @DocumentId
+ private Long id;
+
+ @Field(index=Index.TOKENIZED)
+ private String street;
+
+ @Field(index=Index.TOKENIZED)
+ private String city;
+
<emphasis role="bold">@IndexedEmbedded(depth = 1, prefix =
"ownedBy_")</emphasis>
private Owner ownedBy;
@@ -199,10 +256,11 @@
<para>The default prefix is <literal>propertyName.</literal>,
following
the traditional object navigation convention. You can override it using
- the <literal>prefix</literal> attribute.</para>
+ the <literal>prefix</literal> attribute as it is shown on the
+ <literal>ownedBy</literal> property.</para>
<para><literal>depth</literal> is necessary when the object
graph
- contains a cyclic dependency of classes (not instance). For example, if
+ contains a cyclic dependency of classes (not instances). For example, if
<classname>Owner</classname> points to
<classname>Place</classname>.
Hibernate Search will stop including Indexed embedded atttributes after
reaching the expected depth (or is the object graph boundaries are
@@ -211,8 +269,9 @@
1, any <literal>@IndexedEmbedded</literal> attribute in Owner (if any)
will be ignored.</para>
- <para>Such a mapping is very useful to express queries refering to
- associated objects, such as:</para>
+ <para>Such a feature (<literal>@IndexedEmbedded</literal>) is
very
+ useful to express queries refering to associated objects, such
+ as:</para>
<itemizedlist>
<listitem>
@@ -249,6 +308,15 @@
associated entity is updated (in ou example, a
<literal>Place</literal>
index document has to be updated when the associated
<classname>Address</classname> instance is updated.</para>
+
+ <note>
+ <para><literal>@IndexedEmbedded</literal> is supported on
collections
+ too (ie to index associated object included in collections). But the
+ support is only partially implemented. It will depend on how you
+ update collections (Check HSEARCH-56 in JIRA for more informations).
+ The workaround is to manually index the object
+ (session.index())</para>
+ </note>
</section>
<section>
@@ -302,10 +370,9 @@
<para>All field of a full text index in Lucene have to be represented as
Strings. Ones Java properties have to be indexed in a String form. For
- most of your properties, Hibernate Search does
- the translation job for you thanks to a built-in set of bridges. In some
- cases, though you need a fine grain control over the translation
- process.</para>
+ most of your properties, Hibernate Search does the translation job for you
+ thanks to a built-in set of bridges. In some cases, though you need a fine
+ grain control over the translation process.</para>
<section>
<title>Built-in bridges</title>
Modified: trunk/HibernateExt/search/doc/reference/en/modules/query.xml
===================================================================
--- trunk/HibernateExt/search/doc/reference/en/modules/query.xml 2007-05-30 20:25:23 UTC
(rev 11599)
+++ trunk/HibernateExt/search/doc/reference/en/modules/query.xml 2007-05-31 02:48:08 UTC
(rev 11600)
@@ -1,17 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
-<chapter id="search-query">
+<chapter id="search-query" xreflabel="Querying">
<title>Querying</title>
<para>The second most important capability of <productname>Hibernate
Search
</productname> is the ability to execute a Lucene query and retrieve
entities managed by an Hibernate session, providing the power of Lucene
- without living the Hibernate paradygm, and giving another dimension to the
+ without living the Hibernate paradigm, and giving another dimension to the
Hibernate classic search mechanisms (HQL, Criteria query, native SQL
query).</para>
<para>To access the <productname>Hibernate Search</productname>
querying
facilities, you have to use an Hibernate
- <classname>FullTextSession</classname> . A SearchSession wrap an regular
+ <classname>FullTextSession</classname> . A Search Session wrap an regular
<classname>org.hibernate.Session</classname> to provide query and indexing
capabilities.</para>
@@ -30,33 +30,257 @@
List result = fullTextQuery.list(); //return a list of managed objects
</programlisting>
<para>The Hibernate query built on top of the Lucene query is a regular
- <literal>org.hibernate.Query</literal> , you are is the same paradygm as
the
+ <literal>org.hibernate.Query</literal> , you are is the same paradigm as
the
other Hibernate query facilities (HQL, Native or Criteria). The regular
<literal>list()</literal> , <literal>uniqueResult()</literal>
,
<literal>iterate()</literal> and <literal>scroll()</literal>
can be
used.</para>
- <para>If you expect a reasonnable result number and expect to work on all of
- them, <methodname>list()</methodname> or
- <methodname>uniqueResult()</methodname> are recommanded.
- <methodname>list()</methodname> work best if the entity
- <literal>batch-size</literal> is set up properly. Note that Hibernate
Seach
- has to process all Lucene Hits elements when using
- <methodname>list()</methodname> ,
<methodname>uniqueResult()</methodname>
- and <methodname>iterate()</methodname> . If you wish to minimize Lucene
- document loading, <methodname>scroll()</methodname> is more appropriate,
- Don't forget to close the <classname>ScrollableResults</classname>
object
- when you're done, since it keeps Lucene resources.</para>
+ <section>
+ <title>Building queries</title>
- <para>An efficient way to work with queries is to use pagination. The
- pagination API is exactly the one available in
- <classname>org.hibernate.Query</classname> :</para>
+ <para>Hibernate Search queries are built on top of a Lucene query. It
+ gives you a total freedom on the kind of Lucene queries you are willing to
+ execute. However, once built, Hibernate Search abstract the query
+ processing from your application using org.hibernate.Query as your primary
+ query manipulation API.</para>
- <programlisting><emphasis role="bold">org.hibernate.Query
fullTextQuery = fullTextSession.createFullTextQuery( luceneQuery );
- </emphasis>
-fullTextQuery.setFirstResult(30);
-fullTextQuery.setMaxResult(20);
-fullTextQuery.list(); //will return a list of 20 elements starting from the 30th
</programlisting>
+ <section>
+ <title>Building a Lucene query</title>
- <para>Only the relevant Lucene Documents are accessed.</para>
+ <para>This subject is generally speaking out of the scope of this
+ documentation. Please refer to the Lucene documentation or Lucene In
+ Action.</para>
+ </section>
+
+ <section>
+ <title>Building an Hibernate Search query</title>
+
+ <section>
+ <title>Generality</title>
+
+ <para>Once the Lucene query is built, it needs to be wrapped into an
+ Hibernate Query.</para>
+
+ <programlisting>FullTextSession fullTextSession =
Search.createFullTextSession( session );
+org.hibernate.Query fullTextQuery = fullTextSession.createFullTextQuery( luceneQuery
);</programlisting>
+
+ <para>If not specified, the query will be applied on all indexed,
+ potentially returning all types of indexed classes. It is advised, for
+ a performance point of view to restrict the returned types:</para>
+
+ <programlisting>org.hibernate.Query fullTextQuery =
fullTextSession.createFullTextQuery( luceneQuery, Customer.class );
+//or
+fullTextQuery = fullTextSession.createFullTextQuery( luceneQuery, Item.class, Actor.class
);</programlisting>
+
+ <para>The first example returns only matching customers, the second
+ returns matching actors and items.</para>
+ </section>
+
+ <section>
+ <title>Pagination</title>
+
+ <para>It is recommended to restrict the number of returned objects per
+ query. It is a very common use case as well, the user usually navigate
+ from one page to an other. The way to define pagination is exactly the
+ way you would define pagination in a plain HQL or Criteria
+ query.</para>
+
+ <programlisting>org.hibernate.Query fullTextQuery =
fullTextSession.createFullTextQuery( luceneQuery, Customer.class );
+fullTextQuery.setFirstResult(15); //start from the 15th element
+fullTextQuery.setMaxResults(10); //return 10 elements</programlisting>
+
+ <note>
+ <para>It is still possible to get the total number of matching
+ elements regardless of the pagination. See
+ <methodname>getResultSize()</methodname> below</para>
+ </note>
+ </section>
+
+ <section>
+ <title>Sorting</title>
+
+ <para>Apache Lucene provides a very flexible and powerful way to sort
+ results. While the default sorting (by relevance) is appropriate most
+ of the time, it can interesting to sort by one or several
+ properties.</para>
+
+ <para>Inject the Lucene Sort object to apply a Lucene sorting strategy
+ to an Hibernate Search.</para>
+
+ <programlisting>org.hibernate.search.FullTextQuery query =
s.createFullTextQuery( query, Book.class );
+org.apache.lucene.search.Sort sort = new Sort(new SortField("title"));
+<emphasis role="bold">query.setSort(sort);</emphasis>
+List results = query.list();</programlisting>
+
+ <para>One can notice the <classname>FullTextQuery</classname>
+ interface which is a sub interface of
+ <classname>org.hibernate.Query</classname>.</para>
+
+ <para>Fields used for sorting ust not be tokenized.</para>
+ </section>
+
+ <section>
+ <title>Fetching strategy</title>
+
+ <para>When you restrict the return types to one class, Hibernate
+ Search load the objects and respect the static fetching strategy
+ defined in your domain model using a single query.</para>
+
+ <para>It is often useful, however, to refine the fetching strategy for
+ a specific use case.</para>
+
+ <programlisting>Criteria criteria = s.createCriteria( Book.class
).setFetchMode( "authors", FetchMode.JOIN );
+s.createFullTextQuery( luceneQuery ).setCriteriaQuery( criteria
);</programlisting>
+
+ <para>In this example, the query will return all Books matching the
+ luceneQuery. The authors collection will be loaded from the same query
+ using an SQL outer join.</para>
+
+ <para>When defining a criteria query, it is not needed to restrict the
+ entity types returned while creating the Hibernate Search query from
+ the full text session: the type is guessed from the criteria query
+ itself.</para>
+
+ <para>One cannot use <methodname>setCriteriaQuery</methodname>
if more
+ than one entity type is expected to be returned.</para>
+ </section>
+
+ <section>
+ <title>Projection</title>
+
+ <para>For some use cases, returning the domain object (graph) is
+ overkill. Only a small subset of the properties is necessary.
+ Hibernate Search allows you to return only some properties:</para>
+
+ <programlisting>org.hibernate.search.FullTextQuery query =
s.createFullTextQuery( luceneQuery, Book.class );
+query.<emphasis role="bold">setIndexProjection( "id",
"summary", "body", "mainAuthor.name" )</emphasis>;
+List results = query.list();
+Object[] firstResult = (Object[]) results.get(0);
+Integer id = firstResult[0];
+String summary = firstResult[1];
+String body = firstResult[2];
+String authorName = firstResult[3];</programlisting>
+
+ <para>Hibernate Search extracts the properties from the Lucene index
+ and convert them back to their object representation, returning a list
+ of <classname>Object[]</classname>. Projections avoid a potential
+ database round trip (useful if the query response time is critical),
+ but has some constraints:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>the properties projected must be stored in the index
+ (<literal>(a)Field(store=Store.YES)</literal>), which increase the
+ index size</para>
+ </listitem>
+
+ <listitem>
+ <para>the properties projected must use a
+ <literal>FieldBridge</literal> implementing
+
<classname>org.hibernate.search.bridge.TwoWayFieldBridge</classname>
+ or
+
<literal>org.hibernate.search.bridge.TwoWayStringBridge</literal>,
+ the latter being the simpler version</para>
+ </listitem>
+ </itemizedlist>
+
+ <para></para>
+ </section>
+ </section>
+ </section>
+
+ <section>
+ <title>Retrieving the results</title>
+
+ <para>Once the Hibernate Search query is built, executing it is in no way
+ different than executing a HQL or Criteria query. The same paradigm and
+ object semantic apply. All the common operations are available:
+ <methodname>list()</methodname>,
<methodname>uniqueResult()</methodname>,
+ <methodname>iterate()</methodname>,
+ <methodname>scroll()</methodname>.</para>
+
+ <section>
+ <title>Performance considerations</title>
+
+ <para>If you expect a reasonable result number (for example using
+ pagination) and expect to work on all of them,
+ <methodname>list()</methodname> or
+ <methodname>uniqueResult()</methodname> are recommended.
+ <methodname>list()</methodname> work best if the entity
+ <literal>batch-size</literal> is set up properly. Note that Hibernate
+ Search has to process all Lucene Hits elements (within the pagination)
+ when using <methodname>list()</methodname> ,
+ <methodname>uniqueResult()</methodname> and
+ <methodname>iterate()</methodname>. If you wish to minimize Lucene
+ document loading, <methodname>scroll()</methodname> is more
appropriate,
+ Don't forget to close the <classname>ScrollableResults</classname>
+ object when you're done, since it keeps Lucene resources. Pagination is
+ a preferred method over scrolling though.</para>
+ </section>
+
+ <section>
+ <title>Result size</title>
+
+ <para>It is sometime useful to know the total number of matching
+ documents:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>for the Google-like feature 1-10 of about 888,000,000
</para>
+ </listitem>
+
+ <listitem>
+ <para>to implement a fast pagination navigation</para>
+ </listitem>
+
+ <listitem>
+ <para>to implement a multi step search engine (adding approximation
+ if the restricted query return no or not enough results)</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>But it would be costly to retrieve all the matching
+ documents.</para>
+
+ <para>Hibernate Search allows you to retrieve the total number of
+ matching documents regardless of the pagination parameters. Even more
+ interesting, you can retrieve the number of matching elements without
+ even triggering a single object load.</para>
+
+ <programlisting>org.hibernate.search.FullTextQuery query =
s.createFullTextQuery( luceneQuery, Book.class );
+assert 3245 == <emphasis
role="bold">query.getResultSize()</emphasis>; //return the number of
matching books without loading a single one
+
+org.hibernate.search.FullTextQuery query = s.createFullTextQuery( luceneQuery, Book.class
);
+query.setMaxResult(10);
+List results = query.list();
+assert 3245 == <emphasis
role="bold">query.getResultSize()</emphasis>; //return the total number
of matching books regardless of pagination</programlisting>
+
+ <para></para>
+ </section>
+ </section>
+
+ <section>
+ <title>Optimizing the query process</title>
+
+ <para>Query performance depends on several criteria:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>the Lucene query itself: read the literature on this
+ subject</para>
+ </listitem>
+
+ <listitem>
+ <para>the number of object loaded: use pagination (always ;-) ) or
+ index projection (if needed)</para>
+ </listitem>
+
+ <listitem>
+ <para>the way Hibernate Search interacts with the Lucene readers:
+ defines the appropriate <xref
+ linkend="search-architecture-readerstrategy" />.</para>
+ </listitem>
+ </itemizedlist>
+ </section>
</chapter>
\ No newline at end of file
Modified:
trunk/HibernateExt/search/src/java/org/hibernate/search/reader/ReaderProvider.java
===================================================================
---
trunk/HibernateExt/search/src/java/org/hibernate/search/reader/ReaderProvider.java 2007-05-30
20:25:23 UTC (rev 11599)
+++
trunk/HibernateExt/search/src/java/org/hibernate/search/reader/ReaderProvider.java 2007-05-31
02:48:08 UTC (rev 11600)
@@ -12,6 +12,8 @@
* <p/>
* Not that the reader must be closed once opened.
*
+ * The ReaderProvider implementation must have a no-arg constructor
+ *
* @author Emmanuel Bernard
*/
public interface ReaderProvider {