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)

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