Querying Data with Ickle and Protobuf

What You Will Learn

How to define Protobuf schemas with @Proto annotations, create indexed caches, and run Ickle queries including WHERE clauses, projections, and DELETE operations.

Prerequisites

  • Java 17+

  • An Infinispan Server running on localhost:11222 (or Docker/Podman available for Testcontainers)

Start an Infinispan Server with Docker or Podman:

docker run -it --rm -p 11222:11222 -e USER=admin -e PASS=password quay.io/infinispan/server:latest
Tip
You can replace docker with podman in the command above if you use Podman.
Tip
If no server is running, the tutorial code automatically starts an Infinispan Server using Testcontainers.

Step 1: Define Your Data Model with Protobuf Annotations

Infinispan uses Protobuf for serialization. Define your entities as Java records with @Proto and @Indexed annotations. The Person entity uses @Keyword annotations for indexed fields, and the PersonKey record defines a composite key with @Basic projectable fields. A @ProtoSchema interface generates the schema for both:

@Proto
@Indexed(keyEntity = "tutorial.PersonKey")
public record Person(@Keyword(projectable = true, sortable = true, normalizer = "lowercase", indexNullAs = "unnamed", norms = false)
                     String firstName,
                     @Keyword(projectable = true, sortable = true, normalizer = "lowercase", indexNullAs = "unnamed", norms = false)
                     String lastName,
                     int bornYear,
                     @Keyword(projectable = true, sortable = true, normalizer = "lowercase", indexNullAs = "unnamed", norms = false)
                     String bornIn
) {}

Step 2: Connect and Create an Indexed Cache

Register the Protobuf context initializer, configure the indexed cache with indexing enabled="true", and connect:

   static void connectToInfinispan() throws Exception {
      ConfigurationBuilder builder = TutorialsConnectorHelper.connectionConfig();

      // Add the Protobuf serialization context in the client
      builder.addContextInitializer(new TutorialSchemaImpl());

      // Use indexed cache
      URI indexedCacheURI = InfinispanRemoteQuery.class.getClassLoader().getResource("indexedCache.xml").toURI();
      builder.remoteCache(INDEXED_PEOPLE_CACHE).configurationURI(indexedCacheURI);

      // Connect to the server
      client = TutorialsConnectorHelper.connect(builder);

      // Create and add the Protobuf schema in the server
      addPersonSchema(client);

      // Get the people cache, create it if needed with the default configuration
      peopleCache = client.getCache(INDEXED_PEOPLE_CACHE);
   }

Step 3: Run Ickle Queries

Query all entries, filter with parameters, use projections, and delete by query:

   static List<Person> queryAll() {
      // Query all
      Query<Person> query = peopleCache.query("FROM tutorial.Person");
      List<Person> queryResult = query.execute().list();
      // Print the results
      System.out.println("SIZE " + queryResult.size());
      System.out.println(queryResult);
      return queryResult;
   }

   static List<Person> queryWithWhereStatementOnValues() {
      // Create a query with lastName parameter
      System.out.println("== Query on values");
      Query<Person> query = peopleCache.query("FROM tutorial.Person p where p.lastName = :lastName");
      // Set the parameter value
      query.setParameter("lastName", "Granger");
      // Execute the query
      List<Person> queryResult = query.execute().list();
      // Print the results
      System.out.println(queryResult);
      return queryResult;
   }

   static List<PersonDTO> queryWithProjection() {
      // Create a query with projection
      System.out.println("== Query with key and values projection");
      Query<Object[]> queryProjection = peopleCache.query("SELECT p.key.pseudo, p.firstName, p.lastName FROM tutorial.Person p where p.bornIn = 'London'");
      // Execute the queryProjection
      List<PersonDTO> queryResultProjection = queryProjection.execute().list()
              .stream()
              .map(r -> new PersonDTO(r[0] + "", r[1] + " " + r[2]))
              .toList();
      // Print the results queryResultProjection
      System.out.println(queryResultProjection);
      return queryResultProjection;
   }

   static List<Person> deleteByQuery() {
      Query<Person> query = peopleCache.query("DELETE FROM tutorial.Person p where p.key.pseudo = 'dmalfoy'");
      System.out.println("== DELETE count:" + query.execute().count().value());
      // Query all
      query = peopleCache.query("FROM tutorial.Person");
      List<Person> queryResult = query.execute().list();
      // Print the results
      System.out.println("SIZE " + queryResult.size());
      System.out.println(queryResult);
      return queryResult;
   }

Step 4: Run the Tutorial

mvn package exec:java

What’s Next