Apache Ignite Documentation

GridGain Developer Hub - Apache Ignitetm

Welcome to the Apache Ignite developer hub run by GridGain. Here you'll find comprehensive guides and documentation to help you start working with Apache Ignite as quickly as possible, as well as support if you get stuck.

 

GridGain also provides Community Edition which is a distribution of Apache Ignite made available by GridGain. It is the fastest and easiest way to get started with Apache Ignite. The Community Edition is generally more stable than the Apache Ignite release available from the Apache Ignite website and may contain extra bug fixes and features that have not made it yet into the release on the Apache website.

 

Let's jump right in!

 

Documentation     Ask a Question     Download

 

Javadoc     Scaladoc     Examples

Cache Queries

Query distributed caches using SQL, TEXT, or PREDICATE based queries.

Ignite supports distributed cache queries allowing you to retrieve data from cache based on some user defined criteria.

How it Works

  • The requested query is sent to each node in the cluster.
  • Each node queries its own cache for entries that satisfy the given condition.
  • The query requester consolidates the results received from each node into a single set.

Types of Queries

Ignite provides a very elegant query API with support for

For SQL queries, Ignite supports in-memory indexing so all the data lookups are extremely fast. If you are caching your data in off-heap memory, then query indexes will also be cached in off-heap memory as well.

Ignite also provides support for custom indexing via IndexingSpi and SpiQuery class.

Main Abstractions

IgniteCache has several query methods all of which receive some sublcass of Query class and return QueryCursor.

Query

Query abstract class represents an abstract paginated query to be executed on the distributed cache. You can set the page size for the returned cursor via Query.setPageSize(...) method (default is 1024).

QueryCursor

QueryCursor represents query result set and allows for transparent page-by-page iteration. Whenever user starts iterating over the last page, it will automatically request the next page in the background. For cases when pagination is not needed, you can use QueryCursor.getAll() method which will fetch the whole query result and store it in a collection.

Closing Cursors

Cursors will close automatically if you iterate to the end of the result set. If you need to stop iteration sooner, you must close() the cursor explicitly or use AutoCloseable syntax.

Scan Queries

Scan queries allow for querying cache in distributed form based on some user defined predicate.

IgniteCache<Long, Person> cache = ignite.cache("mycache");

// Find only persons earning more than 1,000.
try (QueryCursor cursor = cache.query(new ScanQuery((k, p) -> p.getSalary() > 1000)) {
  for (Person p : cursor)
    System.out.println(p.toString());
}
IgniteCache<Long, Person> cache = ignite.cache("mycache");

// Find only persons earning more than 1,000.
IgniteBiPredicate<Long, Person> filter = new IgniteByPredicate<>() {
  @Override public boolean apply(Long key, Perons p) {
  	return p.getSalary() > 1000;
	}
};

try (QueryCursor cursor = cache.query(new ScanQuery(filter)) {
  for (Person p : cursor)
    System.out.println(p.toString());
}

SQL Queries

Ignite supports free-form SQL queries virtually without any limitations. SQL syntax is ANSI-99 compliant. You can use any SQL function, any aggregation, any grouping and Ignite will figure out where to fetch the results from.

SQL Joins

Ignite supports distributed SQL joins. Moreover, if data resides in different caches, Ignite allows for cross-cache joins as well.

Joins between PARTITIONED and REPLICATED caches always work without any limitations. However, if you do a join between two PARTITIONED data sets, then you must make sure that the keys you are joining on are collocated.

Field Queries

Instead of selecting the whole object, you can choose to select only specific fields in order to minimize network and serialization overhead. For this purpose Ignite has a concept of fields queries.

Cross-Cache Queries

You can query data from multiple caches. In this case, cache names act as schema names in regular SQL. This means all caches can be referred by cache names in quotes. The cache on which the query was created acts as the default schema and does not need to be explicitly specified.

IgniteCache<Long, Person> cache = ignite.cache("mycache");

SqlQuery sql = new SqlQuery(Person.class, "salary > ?");

// Find only persons earning more than 1,000.
try (QueryCursor<Entry<Long, Person>> cursor = cache.query(sql.setArgs(1000))) {
  for (Entry<Long, Person> e : cursor)
    System.out.println(e.getValue().toString());
}
IgniteCache<Long, Person> cache = ignite.cache("mycache");

// SQL join on Person and Organization.
SqlQuery sql = new SqlQuery(Person.class,
  "from Person, Organization "
  + "where Person.orgId = Organization.id "
  + "and lower(Organization.name) = lower(?)");

// Find all persons working for Ignite organization.
try (QueryCursor<Entry<Long, Person>> cursor = cache.query(sql.setArgs("Ignite"))) {
  for (Entry<Long, Person> e : cursor)
    System.out.println(e.getValue().toString());
}
IgniteCache<Long, Person> cache = ignite.cache("mycache");

SqlFieldsQuery sql = new SqlFieldsQuery("select concat(firstName, ' ', lastName) from Person");

// Select concatinated first and last name for all persons.
try (QueryCursor<List<?>> cursor = cache.query(sql)) {
  for (List<?> row : cursor)
    System.out.println("Full name: " + row.get(0));
}
IgniteCache<Long, Person> cache = ignite.cache("mycache");

// Select with join between Person and Organization.
SqlFieldsQuery sql = new SqlFieldsQuery(
  "select concat(firstName, ' ', lastName), Organization.name "
  + "from Person, Organization where "
  + "Person.orgId = Organization.id and "
  + "Person.salary > ?");

// Only find persons with salary > 1000.
try (QueryCursor<List<?>> cursor = cache.query(sql.setArgs(1000))) {
  for (List<?> row : cursor)
    System.out.println("personName=" + row.get(0) + ", orgName=" + row.get(1));
}
// In this example, suppose Person objects are stored in a 
// cache named 'personCache' and Organization objects 
// are stored in a cache named 'orgCache'.

IgniteCache<Long, Person> personCache = ignite.cache("personCache");

// Select with join between Person and Organization to 
// get the names of all the employees of a specific organization.
SqlFieldsQuery sql = new SqlFieldsQuery(
    "select Person.name  "
        + "from Person, \"orgCache\".Organization where "
        + "Person.orgId = Organization.id "
        + "and Organization.name = ?");

// Execute the query and obtain the query result cursor.
try (QueryCursor<List<?>> cursor =  personCache.query(sql.setArgs("Ignite"))) {
    for (List<?> row : cursor)
        System.out.println("Person name=" + row);
}

Text Queries

Ignite also supports text-based queries based on Lucene indexing.

IgniteCache<Long, Person> cache = ignite.cache("mycache");

// Query for all people with "Master Degree" in their resumes.
TextQuery txt = new TextQuery(Person.class, "Master Degree");

try (QueryCursor<Entry<Long, Person>> masters = cache.query(txt)) {
  for (Entry<Long, Person> e : cursor)
    System.out.println(e.getValue().toString());
}

Query Configuration By Annotations

Indexes can be configured from code by using @QuerySqlField annotations. To tell Ignite which types should be indexed, key-value pairs can be passed into CacheConfiguration.setIndexedTypes(MyKey.class, MyValue.class) method. Note that this method accepts only pairs of types, one for key class and another for value class.

public class Person implements Serializable {
  /** Person ID (indexed). */
  @QuerySqlField(index = true)
  private long id;

  /** Organization ID (indexed). */
  @QuerySqlField(index = true)
  private long orgId;

  /** First name (not-indexed). */
  @QuerySqlField
  private String firstName;

  /** Last name (not indexed). */
  @QuerySqlField
  private String lastName;

  /** Resume text (create LUCENE-based TEXT index for this field). */
  @QueryTextField
  private String resume;

  /** Salary (indexed). */
  @QuerySqlField(index = true)
  private double salary;
  
  ...
}

Query Configuration By CacheTypeMetadata

Indexes and fields also could be configured with org.apache.ignite.cache.CacheTypeMetadata.

<bean class="org.apache.ignite.configuration.IgniteConfiguration">
...
 <!-- Cache configuration. -->
 <property name="cacheConfiguration">
  <list>
   <bean class="org.apache.ignite.configuration.CacheConfiguration">
	  <property name="name" value="my_cache"/>
...
     <!-- Cache types metadata. -->
     <list>
      <bean class="org.apache.ignite.cache.CacheTypeMetadata">
        <!-- Type to query. -->
        <property name="valueType" value="org.apache.ignite.examples.datagrid.store.Person"/>
        <!-- Fields to be queried. -->
        <property name="queryFields">
        <map>
         <entry key="id" value="java.util.UUID"/>
         <entry key="orgId" value="java.util.UUID"/>
         <entry key="firstName" value="java.lang.String"/>
         <entry key="lastName" value="java.lang.String"/>
         <entry key="resume" value="java.lang.String"/>
         <entry key="salary" value="double"/>
        </map>
       </property>
        <!-- Fields to index in ascending order. -->
       <property name="ascendingFields">
        <map>
         <entry key="id" value="java.util.UUID"/>
         <entry key="orgId" value="java.util.UUID"/>
         <entry key="salary" value="double"/>
        </map>
       </property>
       <-- Fields to index as text. -->
       <property name="textFields">
        <list>
         <value>resume</value>
        </list>
      </bean>
     </list>
...
  </list>
 </property>
...
</bean>
CacheConfiguration ccfg = new CacheConfiguration();
....
Collection<CacheTypeMetadata> types = new ArrayList<>();

CacheTypeMetadata type = new CacheTypeMetadata();
type.setValueType(Person.class.getName());

Map<String, Class<?>> qryFlds = type.getQueryFields();
qryFlds.put("id", UUID.class);
qryFlds.put("orgId", UUID.class);
qryFlds.put("firstName", String.class);
qryFlds.put("lastName", String.class);
qryFlds.put("resume", String.class);
qryFlds.put("salary", double.class);

Map<String, Class<?>> ascFlds = type.getAscendingFields();
ascFlds.put("id", UUID.class);
ascFlds.put("orgId", UUID.class);
ascFlds.put("salary", double.class);

Collection<String> txtFlds = type.getTextFields();
txtFlds.add("resume");

types.add(type);
...
ccfg.setTypeMetadata(types);
...

Note, annotations and CacheTypeMetadata are mutually exclusive.

For full example see CacheQueryTypeMetadataExample.

Cache Queries


Query distributed caches using SQL, TEXT, or PREDICATE based queries.

Suggested Edits are limited on API Reference Pages

You can only suggest edits to Markdown body content, but not to the API spec.