Using Infinispan Query API

User Rating: 0 / 5

Star InactiveStar InactiveStar InactiveStar InactiveStar Inactive
 

Applications using a NoSQL storage often need to query data using a full-text search that can be hardly accomplished using traditional RDBMS. This tutorial shows how to use Infinispan Query module in order to search through data added to the cache using an Object oriented fluent API.

In order to do its job, Infinispan uses behind the scenes the popular Apache Lucene and Hibernate search framework.
Apache Lucene is a high-performance, extensible full-text search-engine library written in Java. Hibernate Search encloses Lucene indexing processes into the transaction contexts of Hibernate/JPA, and transparently manages the lifecycle of Lucene Document objects through the event handler mechanism of Hibernate Core.


Let's see with a concrete example how to perform queries using Infinispan Query API. The first thing you need to do, is adding Infinispan query API library to your project, besides the infinispan-core artifactId:

<dependencies>
        <dependency>
            <groupId>org.infinispan</groupId>
            <artifactId>infinispan-core</artifactId>
            <version>${version.infinispan}</version>
        </dependency>
        <dependency>
            <groupId>org.infinispan</groupId>
            <artifactId>infinispan-query</artifactId>
            <version>${version.infinispan}</version>
        </dependency>
</dependencies>

Now you need to annotate your data that you are going to store in your cache. Here's a minimalist Book class:
package com.sample;

import java.io.Serializable;

import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.Indexed;

@Indexed
public class Book implements Serializable {
    
    @Field String title;
    @Field String author;
    @Field String editor;
    public Book(String title, String author, String editor) {
        this.title = title;
        this.author = author;
        this.editor = editor;
    }
    @Override
    public String toString() {
        return "Book [title=" + title + ", author=" + author + ", editor="
                + editor + "]";
    }
}

Most of these annotations are fairly straightforward to understand. @Indexed indicates that we want Hibernate Search to manage indexes for this entity. @Field indicates that a particular property is to be indexed. Now let's write a simple class that stores and retrieves this object from the cache:    
package com.sample;

import java.util.List;

import org.infinispan.Cache;
import org.infinispan.configuration.cache.Configuration;
import org.infinispan.configuration.cache.ConfigurationBuilder;
import org.infinispan.manager.DefaultCacheManager;

import org.infinispan.query.CacheQuery;
import org.infinispan.query.Search;
import org.infinispan.query.SearchManager;

 
public class Application {

   public void testQuery() {
      System.out.println("Demonstrating basic Query usage of Infinispan.");
      
      Configuration infinispanConfiguration = new ConfigurationBuilder()
      .indexing()
         .enable()
         .indexLocalOnly(true)
      .build();

      DefaultCacheManager cacheManager = new DefaultCacheManager(infinispanConfiguration);
      
      Cache<String, Book> cache = cacheManager.getCache();

      cache.put("b1", new Book("hobbit","author","editor"));
      SearchManager qf = Search.getSearchManager(cache);
      
      org.apache.lucene.search.Query luceneQuery = qf.buildQueryBuilderForClass(Book.class)
      .get()
      .phrase()
      .onField("title")
      .sentence("the hobbit")
      .createQuery();
      
      CacheQuery query = qf.getQuery(luceneQuery, Book.class);
      List<Object> list = query.list();
      System.out.println(list);
   }

 
   public static void main(String[] args) throws Exception {
      Application a = new Application();
      a.testQuery();

      System.out.println("Sample complete.");
   }

  
}

This code at first creates a Cache to be used for the example which has index enabled on it. This is mandatory in order to use Infinispan query API. Next we create a SearchManager and QueryBuilder instance, and uses these two to construct a Lucene query.
The Lucene query is then passed to the SearchManager, in order to obtain a CacheQuery instance. This CacheQuery instance, which contains the results to our query, can be converted into a list, can be iterated over, and so on.

As a side note, consider that you can also enable indexes using Infinispan configuration file:

<infinispan>
 <namedCache name="replicated">
   <clustering mode="replicated" />
   <indexing enabled="true" indexLocalOnly="false" />
  </namedCache>
</infinispan>


Advertisement