<infinispan> <default> <indexing enabled="true" indexLocalOnly="false" /> </default> </infinispan>
This document is only relevant to the technology preview of Infinispan Query before version 5, as the API changed. Information about the latest version is here.
This module adds querying capabilities to Infinispan. It uses Hibernate Search and Apache Lucene to index and search objects in the cache. It allows users to obtain objects within the cache without needing to know the keys to each object that they want to obtain, so you can now search your objects basing on some of it's properties, for example to retrieve all red cars (exact metadata match), or all books about a specific topic (full text search and relevance scoring).
Indexing must be enabled in the configuration of the Infinispan cache.
To enable indexing via XML, you need to add the <indexing ... /> element to your <namedCache ... /> or <default ... /> section:
<infinispan> <default> <indexing enabled="true" indexLocalOnly="false" /> </default> </infinispan>
You still need to use the QueryHelper (see code example below) to specify the class types you wish to index. This is transparent to you in Infinispan 5.
import org.infinispan.Cache; import org.infinispan.config.Configuration; import org.infinispan.manager.DefaultCacheManager; import org.infinispan.query.CacheQuery; import org.infinispan.query.QueryFactory; import org.infinispan.query.QueryIterator; import org.infinispan.query.backend.QueryHelper; import java.util.List; import java.util.Properties; public class MyFirstQueryClass { public void queryMyCache() { Configuration cfg = new Configuration(); cfg.setIndexingEnabled(true); // set any other configuration attributes you may need // alternatively, you could configure this using XML Cache c = new DefaultCacheManager(cfg).getCache(); // The QueryHelper must be instantiated before putting objects into the cache. QueryHelper qh = new QueryHelper(c, new Properties(), myClassToQuery.class); // Let's say I have a separate method that puts a bunch of things in the cache as per normal. putStuffInCache(); // When I want to query objects in the cache, I will create a QueryFactory. QueryFactory qf = new QueryFactory(c, qh); // Let's say I'm searching on a field called "name" and looking for "John". CacheQuery cq = qf.getBasicQuery("name", "John"); // Now I can put all my hits into a list! List found = cq.list(); // I can also just get the number of hits that I have. This is cheap as it // doesn't load objects from the cache. int hits = cq.getResultSize(); // The CacheQuery interface has 2 kinds of iterators. They both implement the same interface but // have different implementations under the hood. One loads all hits from the cache first and the // other on the fly. They both implement the QueryIterator interface. QueryIterator eagerIterator = cq.iterator(); QueryIterator lazyIterator = cq.lazyIterator(); // From here, there are various other API methods on the interface. // For example, I can pick out the first and last elements of all my hits. eagerIterator.first(); Object first = eagerIterator.next(); lazyIterator.last(); Object last = lazyIterator.previous(); } }
The query module uses Hibernate Search which in turn uses SLF4J as logging framework. This framework expects users to decide which SLF4J logging implementation they want use, either log4j, jdk...etc. Neither Hibernate Search nor the Infinispan query module make any assumptions which means that if you haven't chosen any implementations, when you start your query module based app, you'll get an exception like this:
Exception in thread "pool-1-thread-1" java.lang.NoClassDefFoundError: org/slf4j/impl/StaticLoggerBinder at org.slf4j.LoggerFactory.getSingleton(LoggerFactory.java:223) at org.slf4j.LoggerFactory.bind(LoggerFactory.java:120) at org.slf4j.LoggerFactory.performInitialization(LoggerFactory.java:111) at org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:269) at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:242) at org.hibernate.search.util.LoggerFactory.make(LoggerFactory.java:38) at org.hibernate.search.Version.<clinit>(Version.java:40) at org.hibernate.search.impl.SearchFactoryImpl.<clinit>(SearchFactoryImpl.java:102) at org.infinispan.query.backend.QueryHelper.<init>(QueryHelper.java:104) at org.infinispan.demo.InfinispanDemo$10.run(InfinispanDemo.java:377) at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) at java.lang.Thread.run(Thread.java:619) Caused by: java.lang.ClassNotFoundException: org.slf4j.impl.StaticLoggerBinder at java.net.URLClassLoader$1.run(URLClassLoader.java:202) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:190) at java.lang.ClassLoader.loadClass(ClassLoader.java:307) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301) at java.lang.ClassLoader.loadClass(ClassLoader.java:248) ... 13 more
To get around it, make sure you select a SLF4J implementation and add the corresponding dependency. For example:
<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.5.8</version> </dependency>
Using @DocumentId to mark a field as identifier is not supported; instead all @Indexed objects should also be marked with @ProvidedId : Infinispan will provide the identifier, which is the key used to store each value in the cache.