Reading Your Own Writes in Java OJAI
The Java OJAI DocumentStore
and Query
APIs provide
the ability to track writes to JSON tables. Use these APIs to ensure your application reads
recent writes on JSON tables with secondary indexes.
Description
You should use this feature if it is important for your query results to reflect synchronized data between a JSON table and its secondary indexes. Because HPE Ezmeral Data Fabric Database updates secondary indexes asynchronously, it is possible for a JSON table and its secondary indexes to become out-of-sync while the index update is in progress.
For example, consider the following scenario:
- Your application updates a JSON table.
- The JSON table includes an
address
field that is a nested document with azipCode
subfield. - You have a secondary index on
zipCode
. - Later in your application, you query the JSON table filtering on
zipCode
.
You want your query result to reflect the updates from earlier in your application. To
achieve this, use the DocumentStore
and Query
APIs that
enable you to retrieve up-to-date information from the index. The APIs synchronize write
operations on the JSON table with read operations on a secondary index.
See Asynchronous Secondary Index Updates for more information about index updates.
API Details
The OJAI DocumentStore
and Query
interfaces provide the
following methods to support this functionality.
DocumentStore.beginTrackingWrites
- Begins tracking the write operations performed through this instance of
DocumentStore
. The method takes an optionalpreviousWritesContext
parameter. If you specify this parameter, the tracking uses that context as the base state. DocumentStore.endTrackingWrites
- Flushes any buffered writes operations for this
DocumentStore
and returns awritesContext
. Use this context to ensure that writes are visible to later queries. You can use the context acrossDocumentStore
objects in the same, as well as different, client processes, when the stores refer to the same JSON table. For example, you can pass thewritesContext
returned by oneDocumentStore
to a secondDocumentStore
, to begin write tracking on the second store. DocumentStore.clearTrackedWrites
- Stops the write tracking and clears any state on this
DocumentStore
instance. Query.waitForTrackedWrites
- Sets the
writesContext
parameter for this query. AwritesContext
allows this query to "see" all the writes that happened inside thewritesContext
of aDocumentStore
.
For the complete API, see Java OJAI Client API.
Read Your Own Writes Example
A complete code example is available on github at OJAI_013_ReadYourOwnWrite.java. The following are code snippets from that example. Each step contains links to corresponding lines of code in the github example:
- Call beginWriteTracking to set the starting point for the commit
context on the JSON table
/demo_table
:// Create an OJAI connection to MapR cluster final Connection connectionNode1 = DriverManager.getConnection("ojai:mapr:"); // Get an instance of OJAI DocumentStore final DocumentStore storeNode1 = connectionNode1.getStore("/demo_table"); // initiate tracking of commit-context storeNode1.beginTrackingWrites();
- Update the
zipCode
of an existing user and insert a new user in/demo_table
:// issue a set of mutations/insert/delete/etc storeNode1.update("user0000", connectionNode1.newMutation().set("address.zipCode", 95110L)); storeNode1.insertOrReplace(connectionNode1.newDocument( "{\"_id\": \"user0004\", \"firstName\": \"Joel\", \"lastName\": \"Smith\", \"age\": 56, \"address\": {\"zipCode\":{\"$numberLong\":95110}}}"));
- Call endWriteTracking to flush the
write operations after step 1, including updates to the secondary
index:
final String commitContext = storeNode1.endTrackingWrites();
The call also returns a
commitContext
. - Issue a query that calls waitForTrackedWrites with the
commitContext
from step 3:/* * Next section of the code can run on the same or on a different node, * the `commitContext` obtained earlier needs to be propagated to that node. */ // Create an OJAI connection to MapR cluster final Connection connectionNode2 = DriverManager.getConnection("ojai:mapr:"); // Get an instance of OJAI DocumentStore final DocumentStore storeNode2 = connectionNode2.getStore("/demo_table"); // Build an OJAI query and set its commit context with timeout of 2 seconds final Query query = connectionNode2.newQuery() .select("_id", "firstName", "lastName", "address.zipCode") .where("{\"$gt\": {\"address.zipCode\": 95110}}") .waitForTrackedWrites(commitContext) .build();
The query filters on the indexed subfield
address.zipCode
. ThecommitContext
ensures that the query result includes the changes made in step 2.