From hibernate-commits at lists.jboss.org Mon Aug 23 13:56:46 2010 Content-Type: multipart/mixed; boundary="===============5483867822974264641==" MIME-Version: 1.0 From: hibernate-commits at lists.jboss.org To: hibernate-commits at lists.jboss.org Subject: [hibernate-commits] Hibernate SVN: r20234 - search/trunk/hibernate-search/src/main/docbook/en-US/modules. Date: Mon, 23 Aug 2010 13:56:45 -0400 Message-ID: <201008231756.o7NHujto028493@svn01.web.mwc.hst.phx2.redhat.com> --===============5483867822974264641== Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Author: epbernard Date: 2010-08-23 13:56:45 -0400 (Mon, 23 Aug 2010) New Revision: 20234 Modified: search/trunk/hibernate-search/src/main/docbook/en-US/modules/query.xml Log: HSEARCH-563 First shot at describing Hibernate Search query DSL Modified: search/trunk/hibernate-search/src/main/docbook/en-US/modules/quer= y.xml =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- search/trunk/hibernate-search/src/main/docbook/en-US/modules/query.xml = 2010-08-23 17:55:53 UTC (rev 20233) +++ search/trunk/hibernate-search/src/main/docbook/en-US/modules/query.xml = 2010-08-23 17:56:45 UTC (rev 20234) @@ -42,7 +42,8 @@ = - Creating a Lucene query + Creating a Lucene query either via the Hibernate Search query = DSL + (recommended) or from scratch = @@ -70,18 +71,40 @@ FullTextSession fullTextSession =3D Search.getFullTextSession(session); = = - The actual search facility is built on native Lucene queries which= the - following example illustrates. + You then have two options to build the full-text query: the Hibern= ate + Search query DSL or the native Lucene query. = + If you use the Hibernate Search query DSL, it will look like + this: + + final QueryBuilder b =3D fullTex= tSession.getSearchFactory().buildQueryBuilder().forEntity( Myth.class ).get= (); +org.apache.lucene.search.Query luceneQuery =3D + b.keyword() + .onField("history").boostedTo(3) + .matching("storm") + .createQuery(); + +org.hibernate.Query fullTextQuery =3D fullTextSession.createFullTextQuery(= luceneQuery ); +List result =3D fullTextQuery.list(); //return a list of managed objects = + + You can alternatively write your Lucene query by hand either using= the + query parser or the programmatic API. If you are considering the + programmatic API, we highly encourage you to use the Hibernate Search qu= ery + DSL (or a mix of both). + - Creating a Lucene query + Creating a Lucene query from scratch via the query parser</titl= e> = - <programlisting>org.apache.lucene.queryParser.QueryParser parser =3D = - new QueryParser("title", new StopAnalyzer() ); + <programlisting><emphasis role=3D"bold">org.apache.lucene.queryParser.= QueryParser parser =3D = + new QueryParser("title", fullTextSession.getSearchFactory().getAnalyze= r(Myth.class) ); +try { + org.apache.lucene.search.Query luceneQuery =3D parser.parse( "history:= storm^3" ); +} +catch (ParseException e) { + //handle parsing failure +}</emphasis> = -org.apache.lucene.search.Query luceneQuery =3D parser.parse( "summary:Fest= ina Or brand:Seiko" ); -<emphasis role=3D"bold">org.hibernate.Query fullTextQuery =3D fullTextSess= ion.createFullTextQuery( luceneQuery ); - </emphasis> +org.hibernate.Query fullTextQuery =3D fullTextSession.createFullTextQuery(= luceneQuery ); List result =3D fullTextQuery.list(); //return a list of managed objects = </programlisting> </example> = @@ -92,8 +115,8 @@ <literal>iterate()</literal> and <literal>scroll()</literal> methods can= be used.</para> = - <para>In case you are using the Java Persistence APIs of Hibernate (aka = EJB - 3.0 Persistence), the same extensions exist:</para> + <para>In case you are using the Java Persistence APIs of Hibernate, the = same + extensions exist:</para> = <example> <title>Creating a Search query using the JPA API @@ -104,12 +127,14 @@ org.hibernate.search.jpa.Search.getFullTextEntityManager(em); = ... -org.apache.lucene.queryParser.QueryParser parser =3D = - new QueryParser("title", new StopAnalyzer() ); +final QueryBuilder b =3D fullTextEntityManager.getSearchFactory().buildQue= ryBuilder().forEntity( Myth.class ).get(); +org.apache.lucene.search.Query luceneQuery =3D + b.keyword() + .onField("history").boostedTo(3) + .matching("storm") + .createQuery(); = -org.apache.lucene.search.Query luceneQuery =3D parser.parse( "summary:Fest= ina Or brand:Seiko" ); javax.persistence.Query fullTextQuery =3D fullText= EntityManager.createFullTextQuery( luceneQuery ); - List result =3D fullTextQuery.getResultList(); //return a list of managed = objects = @@ -128,8 +153,13 @@ manipulation API. =
- Building a Lucene query + Building a Lucene query from scratch = + You have several options: use the query parser (fine for simple + queries) or the Lucene programmatic API (for more complex use cases). + Particularly if you plan on using the programmatic API, we highly + recommend you have a look at the Hibernate Search query DSL. + It is out of the scope of this documentation on how to exactly build a Lucene query. Please refer to the online Lucene documentatio= n or get hold of a copy of either Lucene In Action or Hibernate Search in @@ -137,8 +167,117 @@
=
+ Building a Lucene query with Hibernate Search query DSL</titl= e> + + <para>Writing full-text queries with the Lucene programmatic API is + quite complex. It's even more complex to understand the code once + written. Besides the inherent API complexity, you have to remember to + convert your parameters to their string equivalent as well as make s= ure + to apply the correct analyzer to the right field (an ngram analyzer = will + for example use several ngrams as the tokens for a given word and sh= ould + be searched as such).</para> + + <para>Hibernate Search query DSL make use of a style of API called a + fluent API. This is a fancy name for an API that has a few key + characteristics:</para> + + <itemizedlist> + <listitem> + <para>it has meaningful method names making a succession of + operations reads almost like English</para> + </listitem> + + <listitem> + <para>it limits the options offered to what makes sense in a giv= en + context (thanks to strong typing and IDE autocompletion).</para> + </listitem> + + <listitem> + <para>It often uses the chaining method pattern</para> + </listitem> + + <listitem> + <para>it's easy to use</para> + </listitem> + + <listitem> + <para>it's even easier to read</para> + </listitem> + </itemizedlist> + + <para>Let's see how to use the API. You first need to create a query + builder that is attached to a given indexed entity type. This + <classname>QueryBuilder</classname> will know what analyzer to use a= nd + what field bridge to apply. You can create several + <classname>QueryBuilder</classname>s (one for each entity type invol= ved + in the root of your query. You get the + <classname>QueryBuilder</classname> from the + <classname>SearchFactory</classname>.</para> + + <programlisting>QueryBuilder mythQB =3D searchFactory.buildQueryBuil= der().forEntity( Myth.class ).get();</programlisting> + + <para>You can also override the analyzer used for a given field or + fields. This is rarely needed and should be avoided unless you know = what + you are doing (like many things :)).</para> + + <programlisting>QueryBuilder mythQB =3D searchFactory.buildQueryBuil= der() + .forEntity( Myth.class ) + .overridesForField("history","stem_analyzer_definition"); + .get();</programlisting> + + <para>From the query builder, you are then ready to... build queries. + What's interesting is that we build Lucene queries: you can easily m= ix + and match Lucene's query parser generated <classname>Query</classnam= e> + objects or a <classname>Query</classname> object you have assembled = with + the Lucene programmatic API and use them with the Hibernate Search D= SL + should the DSL be missing some queries.</para> + + <para>Here is how you search for a specific word:</para> + + <programlisting>Query luceneQuery =3D mythQB.keyword().onField("hist= ory").matching("storm").createQuery();</programlisting> + + <para><methodname>keyword()</methodname> means that you are trying to + find a specific word. <methodname>onField()</methodname> tells in wh= ich + lucene field to look. <methodname>matching()</methodname> tells what= to + look for. And finally <methodname>createQuery()</methodname> does cr= eate + the Lucene query object. A lot is going on under this line of code. + First the value storm is passed through the <literal>history</litera= l> + <classname>FieldBridge</classname>: it does not matter here but you = will + see that it's quite handy when dealing with numbers or dates. Second= the + field bridge value is then passed to the analyzer used to index + <literal>history</literal>.</para> + + <para>fluent api contextual autocompletion</para> + + <para>analyzer</para> + + <para>query several words</para> + + <para>ignore analyzer</para> + + <para>field bridge (ignore)</para> + + <para>fuzzy wildcard</para> + + <para>range query (form to above below excludeLimit</para> + + <para>phrase query</para> + + <para>boolean queries (must, should must not, all, except)</para> + + <para>multiple fields</para> + + <para>boosted</para> + + <para>list of options</para> + </section> + + <section> <title>Building a Hibernate Search query = + Let's now see how to build the Hibernate Search query from the + Lucene one. +
Generality = @@ -965,4 +1104,4 @@ run Lucene specific queries. Check for more information.
- \ No newline at end of file + --===============5483867822974264641==--