Search code examples
c#.netignitegridgain

Apache Ignite: How to get cached item without affinity key


I have two caches, one is for Person and another is for Company objects, By specifying the Person.Id as the key and Person.CompanyId as the affinity key.

personCache.Put(new AffinityKey(p1.Id, p1.CompanyId), p1);
companyCache.Put(c1.Id, c1);

Is it possible to get the person from the cache using Person.Id? (without having Person.CompanyId)?


Solution

  • Yes, but not with Key-Value API.

    Key-Value API, by definition, requires a key to access the data. If your key is AffinityKey(personId, companyId) then you have to construct the full key object in order to use the IgniteCache::get operation.

    However, there is also SQL API which is another interface to access the same data. You can declare the cache as an SQL-enabled cache and the personId as an SQL field in that cache.

    There are multiple ways to create an SQL-enabled cache:

    • Create it with the CREATE TABLE statement (as opposed to specifying it in the node config or creating with the createCache method).

    • Specify indexedTypes as a part of the CacheConfiguration and annotate the fields of the key and value objects as @QuerySqlField.
      The problem with indexedTypes is that you have to put annotations into classes. Obviously, this is not going to work with AffinityKey class, as you can't change it.

    • Specify QueryEntity as a part of the CacheConfiguration.
      The problem with QueryEntity is that it may get pretty complex, and it's generally a bit harder to maintain then @QuerySqlField annotations.

    In your case, I would recommend not to use AffinityKey class and create your own version of it - let's call it PersonKey. You can annotate its fields and use indexedTypes.

    Below is a short example:

    public class SqlFieldInKeyExample {
        static class PersonKey {
            @QuerySqlField
            long personId;
    
            @QuerySqlField
            @AffinityKeyMapped
            long companyId;
    
            public PersonKey(long personId, long companyId) {
                this.personId = personId;
                this.companyId = companyId;
            }
        }
    
        static class Person {
            @QuerySqlField
            String name;
    
            public Person(String name) {
                this.name = name;
            }
        }
    
        public static void main(String[] args) throws IgniteException {
            try (Ignite ignite = Ignition.start("examples/config/example-ignite.xml")) {
                CacheConfiguration<PersonKey, Person> cfg = new CacheConfiguration<PersonKey, Person>()
                    .setName("PersonCache")
                    .setIndexedTypes(PersonKey.class, Person.class);
    
                IgniteCache<PersonKey, Person> cache = ignite.createCache(cfg);
    
                cache.put(new PersonKey(9000, 42), new Person("John Doe"));
    
                List<List<?>> result = cache.query(new SqlFieldsQuery("SELECT * FROM PERSON WHERE PERSONID = 9000")).getAll();
                assert result.size() == 1;
                System.out.println(">>>>> Person: " + result.get(0));
            }
        }
    }
    

    Output (among other things) is:

    >>>>> Person: [9000, 42, John Doe]