Thursday, October 18, 2012

Auto complete functionality using Hibernate-Search Module

Search functionality on web should provide results faster otherwise It will create a bad impression to the end user.For this  in case we are using persistent framework like hibernate then we have below two options to make a full text search query
  • Use Criteria API
  • Use Hibernate Search API
If we are operating over large sets of non indexed data, there might be a performance issue. some of the where clause term may not have been indexed in the database. Or say the criteria is like a regular expression for eg name staring with jon*..if we plan to use such queries we should start thinking of a full text search solution like Hibernate Search/Lucene/Solr .

Apache Lucene is a powerful full text search engine. However It has some issue with the object model or say when Object has a parent child relationship or there is a tree like structure in the object to be indexed.

Hibernate Search is combination of Hibernate and Apache Lucene.It handles the shortcoming of apache lucene gracefully.

The ideal scenario for using hibernate search is say when we need auto-complete/search  functionality. where a User will enter some keyword and the application should displaying matching  element in the dropdown

Following are the steps to search a full text search query using Hibernate search API.

  • Creating a search session
  • Creating a Lucene query
  • executing the query.

Configuration
in hiberanate property file  specify index path

<property name="hibernate.search.default.directory_provider"
          value="filesystem"/>

<property name="hibernate.search.default.indexBase"
          value="/var/lucene/indexes"/>
         

Entity configuration          
 package example;
...
@Entity
@Indexed
public class Book {

  @Id
  @GeneratedValue
  private Integer id;
 
  @Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
  private String title;
 
  @Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
  private String subtitle;
  @Field(index = Index.YES, analyze=Analyze.NO, store = Store.YES)
  @DateBridge(resolution = Resolution.DAY)
  private Date publicationDate;

  @IndexedEmbedded
  @ManyToMany
  private Set<Author> authors = new HashSet<Author>();

  public Book() {
  }
 
  // standard getters/setters follow here
  ...
}

  • @Indexed marks Book as indexable
  • Index.YES will ensure that the text will be indexed,
  • analyze.YES ensures that the text will be analyzed using the default Lucene analyzer analyzing means chunking a sentence into individual words and potentially excluding common words like 'a' or 'the'.
  •   store=Store.NO, ensures that the actual data will not be stored in the index
  •   The benefit of storing it is the ability to retrieve it via projections
  //Search operation
 Session session = SessionFactoryUtil.getFactory().getCurrentSession();<br>
 //    create a full text session
 FullTextSession fSession = Search.getFullTextSession(session);
 fSession.beginTransaction();
 //    create a luceneQuery with a parser
 QueryParser parser = new QueryParser("title", new StandardAnalyzer());
 Query lucenceQuery = null;
 try {       
 lucenceQuery = parser.parse("content:hibernate");
 } catch (ParseException e) {       
 throw new RuntimeException("Cannot search with query string",e);        }
 //    execute the query
articles = fSession.createFullTextQuery(lucenceQuery, Article.class).list();
        for (Article article : articles) {
        System.out.println(article);        }
        fSession.getTransaction().commit();

        If the field is not tokenized use another approach
        List<Article> articles = fSession.createFullTextQuery(
     new TermQuery(new Term(“title”, “About Hibernate”)), Article.class).list();
        for (Article article : articles) {
            System.out.println(article);
        }

No comments:

Post a Comment