Concourse is a schemaless and distributed version control database with optimistic availability, serializable transactions and full-text search. Concourse provides a more intuitive approach to data management that is easy to deploy, access and scale with minimal tuning while also maintaining the referential integrity and ACID characteristics of traditional database systems.
The concourse jar is available at Maven Central. We recommend using Gradle to handle depenency management for your project.
######build.gradle
repositories {
mavenCentral()
}
dependencies {
compile 'com.cinchapi:concourse-driver-java:0.12.0+'
}
If you prefer to use another dependency manager like Maven or Ivy, then use the following project information when declaring the dependency:
GroupId: com.cinchapi
ArtifactId: concourse-driver-java
Version: 0.12.0+
Alternatively, you can download the latest jar and manually add it to your project's classpath.
The Concourse data model is lightweight and flexible which enables it to support any kind of data at very large scales. Concourse trades unnecessary structural notions of schemas, tables and indexes for a more natural modeling of data based solely on the following concepts:
- Record - A logical grouping of data about a single person, place or thing (i.e. an object). Each record is a collection of key/value pairs that are together identified by a unique primary key.
- Key - An attribute that maps to a set of one or more distinct values. A record can have many different keys and the keys in one record do not affect those in another record.
- Value - A dynamically typed quanity that is associated with a key in a record.
Concourse natively stores most of the Java primitives: boolean, double, float, integer, long, and string (UTF-8). Otherwise, the value of the #toString()
method for the Object is stored.
Concourse supports linking a key in one record to another record using one of the #link
methods. Links are one directional, but it is possible to add two inverse links so simulate bi-directionality.
By default, Concourse conducts every operation in autocommit
mode where every change is immediately written. Concourse also supports the ability to stage a group of operations in transactions that are atomic, consistent, isolated, and durable using the #stage()
, #commit()
and #abort()
methods.
A Timestamp
is a wrapper around a unix timestamp with microsecond precision that is required for historical operations. These objects are compatible with the Joda DateTime API.
You can convert a Joda DateTime to a Timestamp easily using the Timestamp#fromJoda(DateTime)
method.
A Link
is a wrapper around a Long that represents the primary key of a record and distinguishes from simple long values. Links are never taken as parameters to methods, but will be returned from the get or fetch methods if the data was added using one of the link operations.
The Operator
class defines the operators that can be used to build a query criteria in the find methods.
- EQUALS
- NOT_EQUALS
- GREATER_THAN
- GREATER_THAN_OR_EQUALS
- LESS_THAN
- LESS_THAN_OR_EQUALS
- BETWEEN
- REGEX
- NOT_REGEX
- connect - Establish connection and get database handler
- abort - Abort all staged operations and turn on
autocommit
mode - add - Add data that does not exist
- audit - Get a log of revisions
- clear - Clear are values for a key in a record
- commit - Attempt to commit all staged operations and turn on
autocommit
mode - describe - Describe the keys that exist in a record
- exit - Close the connection
- fetch - Fetch all the values contained for a key in a record
- find - Find records that match a query
- get - Get the first contained value for a key in a record
- getServerVersion - Get the release version of the server
- insert - Bulk insert new data into new or existing records
- link - Link one record to another
- ping - Check to see if a record exists
- remove - Remove an existing value
- revert - Atomically revert data to a previous state
- search - Perform a fulltext search
- set - Atomically set a value
- stage - Turn off
autocommit
and stage subsequent operations in a transaction - unlink - Remove a link from one record to another
- verify - Verify that a value exists for a key in a record
- verifyAndSwap - Atomically set a new value if the existing value matches
- verifyOrSet - Atomically set a value if the existing value is not mapped to a key
Create a new client connection using the details provided in concourse_client.yaml. If the configuration file does not exist or does not contain connection information, then the default connection details (admin@localhost:1717) will be used.
the database handler
Concourse concourse = Concourse.connect();
Create a new client connection for username@host:port using password.
- host
- port
- username
- password
the database handler
Concourse concourse = Concourse.connect("localhost", 1717, "admin", "admin");
Discard any changes that are currently staged for commit.
After this function returns, Concourse will return to autocommit
mode and all subsequent changes will be committed immediately.
concourse.stage();
// make some changes
concourse.abort();
Add key as value to record if it is not already contained.
- key
- value
- record
true if value is added
concourse.add("foo", "bar", 1);
Add key as value in each of the records if it is not already contained.
- key
- value
- records
a mapping from each record to a boolean indicating if value is added
concourse.add("foo", "bar", concourse.find("foo", Operator.NOT_EQUALS, "bar"));
Audit record and return a log of revisions.
- record
a mapping from timestamp to a description of a revision
concourse.audit(1);
Audit key in record and return a log of revisions.
- key
- record
a mapping from timestamp to a description of a revision
concourse.audit("foo", 1);
Clear each of the keys in each of the records by removing every value for each key in each record.
- keys
- records
concourse.clear(concourse.describe(1), concourse.find("count", Operator.GREATER_THAN", 0));
Clear each of the keys in record by removing every value for each key.
- keys
- record
concourse.clear(concourse.describe(1), 1);
Clear key in each of the records by removing every value for key in each record.
- key
- records
concourse.clear("foo", concourse.search("foo", "bar"));
Atomically clear key in record by removing each contained value.
- key
- record
concourse.clear("foo", 1);
Attempt to permanently commit all the currently staged changes. This function returns true if and only if all the changes can be successfully applied. Otherwise, this function returns false and all changes are aborted.
After this function returns, Concourse will return to autocommit
mode and all subsequent changes will be committed immediately.
true
if all staged changes are successfully committed
concourse.stage();
// make some changes
if(concourse.commit()){
System.out.println("yay");
}
else{
System.out.println("oops");
}
Describe each of the records and return a mapping from each record to the keys that currently have at least one value.
- records
the populated keys in each record
List<Long> records = new ArrayList<Long>();
records.add(1);
records.add(2);
records.add(3);
concourse.describe(records);
Describe each of the records at timestamp and return a mapping from each record to the keys that currently have at least one value.
- records
- timestamp
the populated keys in each record at timestamp
List<Long> records = new ArrayList<Long>();
records.add(1);
records.add(2);
records.add(3);
concourse.describe(records, Timestamp.fromJoda(Timestamp.now().getJoda().minusDays(3)));
Describe record and return the keys that currently have at least one value.
- record
the populated keys in record
concourse.describe(1);
Describe record at timestamp and return the keys that currently have at least one value.
- record
- timestamp
the populated keys in record at timestamp
concourse.describe(1, Timestamp.fromJoda(Timestamp.now().getJoda().minusDays(3)));
Close the client connection.
concourse.exit();
Fetch each of the keys from each of the records and return a mapping from each record to a mapping from each key to the contained values.
- keys
- records
the contained values for each of the keys in each of the records
Set<String> keys = new HashSet<String>();
keys.add("foo");
keys.add("bar");
keys.add("baz");
Set<Long> records = new HashSet<Long>();
records.add(1);
records.add(2);
records.add(3);
Map<Long, Map<String, Set<Object>>> data = concourse.fetch(keys, records);
Map<Long, Map<String, Set<Object>>> fetch(Collection<String> keys, Collection<Long> records, Timestamp timestamp)
Fetch each of the keys from each of the records at timestamp and return a mapping from each record to a mapping from each key to the contained values.
- keys
- records
- timestamp
the contained values for each of the keys in each of the records at timestamp
Set<String> keys = new HashSet<String>();
keys.add("foo");
keys.add("bar");
keys.add("baz");
Set<Long> records = new HashSet<Long>();
records.add(1);
records.add(2);
records.add(3);
Map<Long, Map<String, Set<Object>>> data = concourse.fetch(keys, records, Timestamp.fromJoda(DateTime.now().minusYears(4)));
Fetch each of the keys from record and return a mapping from each key to the contained values.
- keys
- record
the contained values for each of the keys in record
Set<String> keys = new HashSet<String>();
keys.add("foo");
keys.add("bar");
keys.add("baz");
Map<String, Set<Object>> data = concourse.fetch(keys, 1);
Fetch each of the keys from record at timestamp and return a mapping from each key to the contained values.
- keys
- record
- timestamp
the contained values for each of the keys in record at timestamp
Set<String> keys = new HashSet<String>();
keys.add("foo");
keys.add("bar");
keys.add("baz");
Map<String, Set<Object>> data = concourse.fetch(keys, 1, Timestamp.fromJoda(DateTime.now().minusYears(4)));
Fetch each of the keys from record and return a mapping from each key to the contained values.
- key
- records
the contained values for key in each of the records
Set<Long> records = new HashSet<Long>();
records.add(1);
records.add(2);
records.add(3);
Map<Long, Set<Object>> data = concourse.fetch("foo", records);
Fetch each of the keys from record at timestamp and return a mapping from each key to the contained values.
- key
- records
- timestamp
the contained values for key in each of the records at timestamp
Set<Long> records = new HashSet<Long>();
records.add(1);
records.add(2);
records.add(3);
Map<Long, Set<Object>> data = concourse.fetch("foo", records, Timestamp.fromMicros(13889604150000));
Find key operator value and return the set of records that satisfy the criteria. This is analogous to the SELECT action in SQL.
- key
- operator
- value
the records that match the criteria
concourse.find("age", Operator.GREATHER_THAN_OR_EQUALS, 20);
Find key operator value at timestamp and return the set of records that satisfy the criteria. This is analogous to the SELECT action in SQL.
- key
- operator
- value
- timestamp
the records that match the criteria
concourse.find("age", Operator.GREATHER_THAN_OR_EQUALS, 20, Timestamp.fromJoda(DateTime.now().minusYears(1)));
Find key operator value and value2 and return the set of records that satisfy the criteria. This is analogous to the SELECT action in SQL.
- key
- operator
- value
- value2
the records that match the criteria
concourse.find("age", Operator.BETWEEN, 20, 40);
Find key operator value and value2 at timestamp and return the set of records that satisfy the criteria. This is analogous to the SELECT action in SQL.
- key
- operator
- value
- value2
- timestamp
the records that match the criteria
concourse.find("age", Operator.BETWEEN, 20, 40, Timestamp.fromJoda(DateTime.now().minusMonths(5)));
Get each of the keys from each of the records and return a mapping from each record to a mapping from each key to the first contained value.
- keys
- records
the first contained value for each of the keys in each of the records
Set<String> keys = new HashSet<String>();
keys.add("foo");
keys.add("bar");
keys.add("baz");
Set<Long> records = new HashSet<Long>();
records.add(1);
records.add(2);
records.add(3);
Map<Long, Map<String, Object>> data = concourse.fetch(keys, records);
Map<Long, Map<String, Object>> get(Collection<String> keys, Collection<Long> records, Timestamp timestamp)
Get each of the keys from each of the records at timestamp and return a mapping from each record to a mapping from each key to the first contained value.
- keys
- records
- timestamp
the first contained value for each of the keys in each of the records at timestamp
Set<String> keys = new HashSet<String>();
keys.add("foo");
keys.add("bar");
keys.add("baz");
Set<Long> records = new HashSet<Long>();
records.add(1);
records.add(2);
records.add(3);
Map<Long, Map<String, Object> data = concourse.fetch(keys, records, Timestamp.fromJoda(DateTime.now().minusYears(4)));
Get each of the keys from record and return a mapping from each key to the first contained value.
- keys
- record
the first contained value for each of the keys in record
Set<String> keys = new HashSet<String>();
keys.add("foo");
keys.add("bar");
keys.add("baz");
Map<String, Object> data = concourse.fetch(keys, 1);
Get each of the keys from record at timestamp and return a mapping from each key to the first contained value.
- keys
- record
- timestamp
the first contained value for each of the keys in record at timestamp
Set<String> keys = new HashSet<String>();
keys.add("foo");
keys.add("bar");
keys.add("baz");
Map<String, Object> data = concourse.fetch(keys, 1, Timestamp.fromJoda(DateTime.now().minusYears(4)));
Get each of the keys from record and return a mapping from each key to the first contained value.
- key
- records
the contained value for key in each of the records
Set<Long> records = new HashSet<Long>();
records.add(1);
records.add(2);
records.add(3);
Map<Long, Object> data = concourse.fetch("foo", records);
Get each of the keys from record at timestamp and return a mapping from each key to the first contained value.
- key
- records
- timestamp
the first contained value for key in each of the records at timestamp
Set<Long> records = new HashSet<Long>();
records.add(1);
records.add(2);
records.add(3);
Map<Long, Object> data = concourse.fetch("foo", records, Timestamp.fromMicros(13889604150000));
Return the version of the server to which this client is currently connected.
the server version
System.out.println(concourse.getServerVersion());
Atomically insert they key/value mappings described in the json formatted string into a new record. The JSON formatted string must describe a JSON object that contains one or more keys, each of which maps to a JSON primitive or array of primitives.
the primary key of the newly created record
String json = "{\"array\":[1,2,3],\"boolean\":true,\"number\":123,\"string\":\"Hello World\"}";
concourse.insert(json);
Insert they key/value mappings described in the json formatted string into each of the records. The JSON formatted string must describe a JSON object that contains one or more keys, each of which maps to a JSON primitive or array of primitives.
a mapping from each record to a boolean indicating if the data was successfully inserted
String json = "{\"array\":[1,2,3],\"boolean\":true,\"number\":123,\"string\":\"Hello World\"}";
concourse.insert(json, concourse.find("class", eq, "Human"));
Atomically insert the key/value mappings described in the json formatted string into record. The JSON formatted string must describe a JSON object that contains one or more keys, each of which maps to a JSON primitive or array of primitives.
true if all the data is inserted into record
String json = "{\"array\":[1,2,3],\"boolean\":true,\"number\":123,\"string\":\"Hello World\"}";
concourse.insert(json, 1);
Add a link from key in source to destination.
- key
- source
- destination
true if the link is added
concourse.link("following", 1, 2);
Add a link from key in source to each of the destinations.
- key
- source
- destinations
a mapping from each of the destinations to a boolean indicating if the link is added
concourse.link("following", 1, concourse.find("class", Operator.EQUALS, "user"));
Ping record.
- record
true if record currently has at least one populated key
concourse.ping(1);
Ping each of the records.
- records
a mapping from each of the records to a boolean indicating if the record has at least one populated key
Set<Long> records = new HashSet<Long>();
records.add(1);
records.add(2);
concourse.ping(records);
Remove key as value from record if it is contained.
- key
- value
- record
true if value is removed
concourse.remove("foo", "bar", 1);
Remove key as value in each of the records if it is contained.
- key
- value
- records
a mapping from each record to a boolean indicating if value is removed
concourse.remove("foo", "bar", concourse.find("foo", Operator.EQUALS, "bar"));
Atomically revert key in record to timestamp by creating new revisions that undo the relevant changes that have occurred since timestamp.
- key
- record
- timestamp
concourse.revert("foo", 1, Timestamp.fromJoda(DateTime.now().minusDays(1))));
Revert each of the keys in each of the records to timestamp by creating new revisions that undo the relevant changes that have occurred since timestamp.
- keys
- records
- timestamp
Set<String> keys = new HashSet<String>();
keys.add("foo");
keys.add("bar");
keys.add("baz");
Set<Long> records = new HashSet<Long>();
records.add(1);
records.add(2);
records.add(3);
concourse.revert(keys, records, Timestamp.fromJoda(DateTime.now().minusDays(1))));
Revert each of the keys in record to timestamp by creating new revisions that undo the relevant changes that have occurred since timestamp.
- keys
- record
- timestamp
Set<String> keys = new HashSet<String>();
keys.add("foo");
keys.add("bar");
keys.add("baz");
concourse.revert(keys, 1, Timestamp.fromJoda(DateTime.now().minusDays(1))));
Revert key in each of the records to timestamp by creating new revisions that undo the relevant changes that have occurred since timestamp.
- key
- records
- timestamp
Set<Long> records = new HashSet<Long>();
records.add(1);
records.add(2);
records.add(3);
concourse.revert("foo", records, Timestamp.fromJoda(DateTime.now().minusDays(1))));
Search key for query and return the set of records that match.
- key
- query
the records that match the fulltext search query
Set<Long> matches = concourse.search("name", "joh do");
for(long match : matches){
System.out.println(concourse.get("name", match));
}
Atomically set key as value in record by clearing any currently contained values and adding value.
- key
- value
- record
concourse.set("foo", "bar", 1);
Set key as value in each of the records.
- key
- value
- records
concourse.set("foo", "bar", concourse.find("foo", Operator.NOT_EQUALS, "bar"));
Turn on staging
mode so that are subsequent changes are collected in a staging area before possibly being committed. Staged operations are guaranteed to be reliable, all or nothing units of work that allow correct recovey from failures and provide isolation between clients so that Concourse is always in a consistent state (i.e. a transaction).
After this function returns, Concourse will return to autocommit
mode and all subsequent changes will be committed immediately.
concourse.stage();
// make some changes
Remove link from key in source to destination.
- key
- source
- destination
true if the link is removed
concourse.unlink("friends", 1, 2)
Verify key equals value in record and return true if value is contained for key in record.
- key
- value
- record
true if key equals value in record
if(concourse.verify("foo", "bar", 1){
concourse.set("foo", "baz", 1);
}
Verify key equaled value in record at timestamp and return true if value was contained for key in record.
- key
- value
- record
- timestamp
true if key equaled value in record at timestamp
if(concourse.verify("foo", "bar", 1,
Timestamp.fromJoda(Timestamp.now().getJoda().minusDays(3)))){
concourse.set("foo", "baz", 1);
}
Atomically verify key as expected in record and swap with replacement.
- key
- expeced
- record
- replacement
true if both the verification and swap are successful
int count = concourse.get("count", 1);
concourse.verifyAndSwap("count", count, 1, count++);
Atomically verify key as value in record or set key as value in record.
- key
- value
- record
true if both the verification and swap are successful
int count = concourse.get("count", 1);
concourse.verifyOrSet("count", count, 1, count++);