Skip to content

Kundera OracleNoSQL

xamry edited this page Apr 29, 2013 · 17 revisions

OracleNoSQL is a distributed key-value database. Kundera supports OracleNoSQL (alongwith Redis, which is also a key-value database).

Entity to Key-Value store mapping

Kundera, being a JPA object-mapper, maps entity class instances with data storage structure provided in underlying database.

Below is a simplified depiction of entity class to key-value pair mapping mechanism adopted by Kundera: (This is a result of saving Person entity with personId, personName and age fields set to "1", "John Smith" and 32 respectively).

Entity-KV Store Mapping

Points worth noting:

  1. Schema name defined in entity class is mapped to KV Store name.
  2. Table name and ID column value constitute major key.
  3. Rest of the column names are stored as minor keys.
  4. Value of columns are stored as byte array values.

Configuration

All you have to do is to define persistence unit in persistence.xml file as shown below:

      <persistence-unit name="oracle_nosql_pu">
		<provider>com.impetus.kundera.KunderaPersistence</provider>
		<properties>
			<property name="kundera.nodes" value="localhost" />
			<property name="kundera.port" value="5000" />
			<property name="kundera.client.lookup.class"
				value="com.impetus.client.oraclenosql.OracleNoSQLClientFactory" />
			<property name="kundera.keyspace" value="HR_Store" />
			<property name="kundera.dialect" value="kvstore" />
			<property name="kundera.client" value="kvstore" />
			<property name="kundera.cache.provider.class"
				value="com.impetus.kundera.cache.ehcache.EhCacheProvider" />
			<property name="kundera.cache.config.resource" value="/ehcache-test.xml" />       
			<property name="kundera.indexer.class"
			value="com.impetus.client.oraclenosql.index.OracleNoSQLInvertedIndexer" />
		</properties>
	</persistence-unit>

You may visit here for detailed description of each property.

CRUD

Insert, Find, Update and Remove operations are pure-JPA and are straightforward.

        Person person = new Person();
        person.setPersonId("1");
        person.setPersonName("John Smith");
        person.setAge(32);
        
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("oracle_nosql_pu");
        EntityManager em = emf.createEntityManager();
        
        //Insert data
        em.persist(person);
        
        em.clear();   //Clear cache before finding record
        
        //Search for data
        Person peronFound = em.find(Person.class, "1");        
        
        //Update data
        person.setAge(33);
        em.merge(person);
        
        //Delete data
        em.remove(person);
        
        em.close();
        emf.close();

Storage of Embeddable objects

Columns of embeddable objects are stored in a way similar to regular columns, with the exception that minor keys have two components: (1) Embedded column name, and (2) Column name in embeddable class.

Let's add an embeddable attribute to our Person class, persist person object and see how it's stored in OracleNoSQL.

Person.java

@Entity
@Table(name = "PERSON", schema = "HR_Store@oracle_nosql_pu")
@IndexCollection(columns = {@Index(name = "userName") },{@Index(name = "age") })
public class Person
{
    @Id
    @Column(name = "PERSON_ID")
    private String personId;

    @Column(name = "PERSON_NAME")
    private String personName;

    @Column(name = "AGE")
    private Integer age;

    @Embedded
    private Office office;
    
    //Getters and setters
}

Office.java

@Embeddable
public class Office
{
    @Column
    private int officeId;

    @Column
    private String companyName;

    @Column
    private String location;

    //Getters and Setters
}

Here is how data will look like when person entity is persisted.

/PERSON/1/ - /PERSON_NAME        ---> John Smith
/PERSON/1/ - /AGE                ---> 32
/PERSON/1/ - /office/officeId    ---> L1
/PERSON/1/ - /office/companyName ---> Impetus
/PERSON/1/ - /office/location    ---> San Jose

Inverted Indexing

When we set below property in persistence.xml, an inverted index is built while persisting data. This is done to facilitate searching of columns/ embedded columns using JPA queries (explained in next section):

<property name="kundera.indexer.class"
			value="com.impetus.client.oraclenosql.index.OracleNoSQLInvertedIndexer" />

An illustration of inverted index built by Kundera is given below (Data is similar to Person object from the previous section):

/PERSON_idx/PERSON_NAME/John Smith/ - /1     ---> 1
/PERSON_idx/AGE/32/ - /1                     ---> 1
/PERSON_idx/office.officeId/L1/ - /1         ---> 1
/PERSON_idx/office.companyName/Impetus/ - /1 ---> 1
/PERSON_idx/office.location/San Jose/ - /1   ---> 1

JPA Queries:

Exploiting inverted indexing (or even Lucene Indexing if set using "index.home.dir" property in persistence.xml), Kundera supports JPA queries. Here are some examples:

        Query query = em.createQuery("Select p from Person p");
        List<Person> persons = query.getResultList();
        
        query = em.createQuery("Select p.age from Person p");        
        persons = query.getResultList();
        
        query = em.createQuery("Select p from Person p where p.personName=:personName AND p.age=:age");
        query.setParameter("personName", "John Smith");
        query.setParameter("age", 32);
        persons = query.getResultList();
        
        query = em.createQuery("Select p from Person p where p.age>:min OR p.age<=:max");
        query.setParameter("min", 10);
        query.setParameter("max", 50);
        persons = query.getResultList();

        query = em.createQuery("Select p from Person p where p.personId between :min AND :max");
        query.setParameter("min", 10);
        query.setParameter("max", 50);
        persons = query.getResultList();
        
        query = em.createQuery("Select p from Person p where p.office.companyName=:companyName");
        query.setParameter("companyName", "Impetus");        
        persons = query.getResultList();
        
        query = em.createQuery("Delete from PersonEmbeddedKVStore p");             
        int deleteCount =  query.executeUpdate();

Reading/ writing LOBs

OracleNoSQL supports reading/ writing of Large Objects LOBs such as audio and video files. Using Kundera, you can read/ write LOBs using attribute of type java.io.File in entity classes.

Here is an example:

UserProfile.java

@Entity
@Table(name = "USER_PROFILE", schema = "HR_Store@oracle_nosql_pu")
public class UserProfile
{
    @Id
    @Column(name = "USER_ID")
    private int userId;

    @Column(name = "USER_NAME")
    private String userName;

    @Column(name = "PROFILE_PICTURE")
    private File profilePicture;
    
    public UserProfile(int userId, String userName, File profilePicture)
    {
        super();
        this.userId = userId;
        this.userName = userName;
        this.profilePicture = profilePicture;
    }

    //Getters and setters
}

LOBExample.java (Snippet)

        //Insert user profile alongwith picture
        File file = new File("/home/amresh/MyPhoto.jpg");
        long fileSize = file.getTotalSpace();
        UserProfile userProfile = new UserProfile(1, "Amresh", file);
        em.persist(userProfile);

        //Clear Cache
        em.clear();

        //Find user profile
        UserProfile up = (UserProfile) em.find(UserProfile.class, 1);
        File myPicture = up.getProfilePicture();

        //Delete Profile
        em.remove(userProfile);

Note: Before performing LOB operations, you can configure below parameters that are applied on all operations until em.close() is called. (In absence, default OracleNoSQL settings are applied).

        em.setProperty("write.timeout", 10);
        em.setProperty("durability", Durability.COMMIT_WRITE_NO_SYNC);
        em.setProperty("time.unit", TimeUnit.SECONDS);
        em.setProperty("consistency", Consistency.NONE_REQUIRED);

Our Wishlist

Here is a compilation of what is not supported currently, but we would like to see them in our kitty for Kundera-OracleNoSQL soon:

  1. Element Collections
  2. Composite Keys
  3. Primary Key Auto generation
  4. Schema Generation
  5. Native Queries
  6. Geospatial Persistence and Queries

Also Note:

Home

Clone this wiki locally