Last updated: June 22, 2021
This notebook demonstrates Java Aerospike CRUD operations (Create, Read, Update, Delete) for lists of data, focusing on server-side read and update operations, including sort.
This Jupyter Notebook requires the Aerospike Database running locally with Java kernel and Aerospike Java Client. To create a Docker container that satisfies the requirements and holds a copy of these notebooks, visit the Aerospike Notebooks Repo.
Run these first to initialize Jupyter, download the Java Client, and make sure the Aerospike Database is running.
Make it easier to work with Java in Jupyter.
import io.github.spencerpark.ijava.IJava;
import io.github.spencerpark.jupyter.kernel.magic.common.Shell;
IJava.getKernelInstance().getMagics().registerMagics(Shell.class);
Ensure Aerospike Database is running locally.
%sh asd
Ask Maven to download and install the project object model (POM) of the Aerospike Java Client.
%%loadFromPOM
<dependencies>
<dependency>
<groupId>com.aerospike</groupId>
<artifactId>aerospike-client</artifactId>
<version>5.0.0</version>
</dependency>
</dependencies>
Create an instance of the Aerospike Java Client, and connect to the demo cluster.
The default cluster location for the Docker container is localhost port 3000. If your cluster is not running on your local machine, modify localhost and 3000 to the values for your Aerospike cluster.
import com.aerospike.client.AerospikeClient;
AerospikeClient client = new AerospikeClient("localhost", 3000);
System.out.println("Initialized the client and connected to the cluster.");
Initialized the client and connected to the cluster.
Create and print a String list and an Integer List.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
ArrayList<String> listStr = new ArrayList<String>();
listStr.add("Annette");
listStr.add("Redwood");
listStr.add("Aquamarine");
listStr.add("Pineapple");
System.out.println("String List: " + listStr);
ArrayList<Integer> listInt = new ArrayList<Integer>();
listInt.add(81);
listInt.add(3);
listInt.add(27);
listInt.add(9);
listInt.add(27);
listInt.add(1);
System.out.println("Integer List: " + listInt);
String List: [Annette, Redwood, Aquamarine, Pineapple] Integer List: [81, 3, 27, 9, 27, 1]
A Key uniquely identifies a specific Record in your Aerospike server or cluster. Each key must have a Namespace and optionally a Set name.
The namespace test is configured on your Aerospike server or cluster. The rest can be defined and modified by Aerospike Java Client Code.
For additional information on the Aerospike Data Model, go here.
import com.aerospike.client.Key;
String listSet = "listset1";
String listNamespace = "test";
Integer theKey = 0;
Key key = new Key(listNamespace, listSet, theKey);
System.out.println("Key created." );
Key created.
A Bin is a data field in an Aerospike record.
import com.aerospike.client.Bin;
String listStrBinName = "liststrbin";
String listIntBinName = "listintbin";
Bin bin1 = new Bin(listStrBinName, listStr);
Bin bin2 = new Bin(listIntBinName, listInt);
System.out.println( "Created " + bin1 + " and " + bin2 + ".");
Created liststrbin:[Annette, Redwood, Aquamarine, Pineapple] and listintbin:[81, 3, 27, 9, 27, 1].
import com.aerospike.client.policy.ClientPolicy;
ClientPolicy clientPolicy = new ClientPolicy();
System.out.println("Created a client policy.");
Created a client policy.
client.put(clientPolicy.writePolicyDefault, key, bin1, bin2);
System.out.println("Key: " + theKey + ", " + listStrBinName + ": " + listStr + ", " + listIntBinName + ": " + listInt);
Key: 0, liststrbin: [Annette, Redwood, Aquamarine, Pineapple], listintbin: [81, 3, 27, 9, 27, 1]
Now that the lists are in Aerospike, the client can return full or partial lists from bin contents. No data is modified by these ops.
A record can be retrieved using the key, namespace, and set name.
In the output:
For more information on both generation number and expiration, see the Aerospike FAQ.
import com.aerospike.client.Record;
Key key = new Key(listNamespace, listSet, theKey);
Record record = client.get(null, key);
System.out.println(record);
(gen:1),(exp:359404607),(bins:(liststrbin:[Annette, Redwood, Aquamarine, Pineapple]),(listintbin:[81, 3, 27, 9, 27, 1]))
The Aerospike API contains the operations to get list elements using index and rank.
Aerospike provides operations to read list element(s) by index. As a convenience, the client returns the specified value as the contents of the bin.
Aerospike operations allow indexing forward from the beginning of the list using zero-based numbering. Negative numbers index backwards from the end of a list.
For more examples of indexes, go here.
import com.aerospike.client.Operation;
import com.aerospike.client.Value;
import com.aerospike.client.cdt.ListOperation;
int last = -1;
Key key = new Key(listNamespace, listSet, theKey);
Record record = client.get(null, key);
Record lastString = client.operate(null, key,
ListOperation.get(listStrBinName, last)
);
System.out.println("The string list: " + record.getValue(listStrBinName));
System.out.println("The last string: " + lastString.getValue(listStrBinName));
The string list: [Annette, Redwood, Aquamarine, Pineapple] The last string: Pineapple
import com.aerospike.client.cdt.ListReturnType;
int highestRank = -1;
Key key = new Key(listNamespace, listSet, theKey);
Record record = client.get(null, key);
Record highestRankString = client.operate(null, key,
ListOperation.getByRank(listStrBinName, highestRank, ListReturnType.VALUE)
);
System.out.println("The string list: " + record.getValue(listStrBinName));
System.out.println("The highest rank string: " + highestRankString.getValue(listStrBinName));
The string list: [Annette, Redwood, Aquamarine, Pineapple] The highest rank string: Redwood
Read integer values from the Aerospike Server or Cluster using value range or rank range.
int lowerBound = 3;
int upperBound = 27;
Key key = new Key(listNamespace, listSet, theKey);
Record record = client.get(null, key);
Record between3And27 = client.operate(null, key,
ListOperation.getByValueRange(listIntBinName, Value.get(lowerBound), Value.get(upperBound),
ListReturnType.VALUE)
);
System.out.println("The integer list: " + record.getValue(listIntBinName));
System.out.println("The integers between " + lowerBound + " and " + upperBound + ": "
+ between3And27.getValue(listIntBinName));
The integer list: [81, 3, 27, 9, 27, 1] The integers between 3 and 27: [3, 9]
Aerospike provides operations to return a range of elements by rank. Rank is zero-based.
int secondRank = 1;
int rangeRankSize = 2;
Key key = new Key(listNamespace, listSet, theKey);
Record record = client.get(null, key);
Record rank1And2 = client.operate(client.writePolicyDefault, key,
ListOperation.getByRankRange(listIntBinName, secondRank, rangeRankSize, ListReturnType.VALUE)
);
System.out.println("The integer list: " + record.getValue(listIntBinName));
System.out.println("The 2nd and 3rd ranked integers: " + rank1And2.getValue(listIntBinName));
The integer list: [81, 3, 27, 9, 27, 1] The 2nd and 3rd ranked integers: [9, 3]
Aerospike's list operations can also modify data in the Aerospike Database.
Aerospike's list insert operation inserts before the item at an index, and increases the index of the item at the index and all subsequent items in the list.
String Fish = "Koi";
int secondPosition = 1;
int beforeLastPosition = -1;
Key key = new Key(listNamespace, listSet, theKey);
Record origRecord = client.get(null, key);
System.out.println("Before – " + origRecord.getValue(listStrBinName));
origRecord = client.operate(client.writePolicyDefault, key,
ListOperation.insert(listStrBinName, beforeLastPosition, Value.get(Fish)),
ListOperation.insert(listStrBinName, secondPosition, Value.get(Fish))
);
Record finalRecord = client.get(null, key);
System.out.println(" After – " + finalRecord.getValue(listStrBinName));
Before – [Annette, Redwood, Aquamarine, Pineapple] After – [Annette, Koi, Redwood, Aquamarine, Koi, Pineapple]
int firstPosition = 0;
Key key = new Key(listNamespace, listSet, theKey);
Record origRecord = client.get(null, key);
System.out.println("Before – " + origRecord.getValue(listStrBinName));
origRecord = client.operate(client.writePolicyDefault, key,
ListOperation.remove(listStrBinName, firstPosition)
);
Record finalRecord = client.get(null, key);
System.out.println(" After – " + finalRecord.getValue(listStrBinName));
Before – [Annette, Koi, Redwood, Aquamarine, Koi, Pineapple] After – [Koi, Redwood, Aquamarine, Koi, Pineapple]
int seventeen = 17;
Key key = new Key(listNamespace, listSet, theKey);
Record origRecord = client.get(null, key);
System.out.println("Before – " + origRecord.getValue(listIntBinName));
origRecord = client.operate(client.writePolicyDefault, key,
ListOperation.append(listIntBinName, Value.get(seventeen))
);
Record finalRecord = client.get(null, key);
System.out.println(" After – " + finalRecord.getValue(listIntBinName));
Before – [81, 3, 27, 9, 27, 1] After – [81, 3, 27, 9, 27, 1, 17]
Indexes into lists start at 0.
int incNum = 111;
int incIndex = 3;
Key key = new Key(listNamespace, listSet, theKey);
Record origRecord = client.get(null, key);
System.out.println("Before – " + origRecord.getValue(listIntBinName) );
origRecord = client.operate(client.writePolicyDefault, key,
ListOperation.increment(listIntBinName, incIndex, Value.get(incNum))
);
Record finalRecord = client.get(null, key);
System.out.println(" After – " + finalRecord.getValue(listIntBinName) );
Before – [81, 3, 27, 9, 27, 1, 17] After – [81, 3, 27, 120, 27, 1, 17]
import com.aerospike.client.cdt.ListSortFlags;
Key key = new Key(listNamespace, listSet, theKey);
Record origRecord = client.get(null, key);
System.out.println("Unsorted – " + origRecord.getValue(listStrBinName));
origRecord = client.operate(client.writePolicyDefault, key,
ListOperation.sort(listStrBinName, ListSortFlags.DROP_DUPLICATES)
);
Record finalRecord = client.get(null, key);
System.out.println(" Sorted – " + finalRecord.getValue(listStrBinName));
Unsorted – [Koi, Redwood, Aquamarine, Koi, Pineapple] Sorted – [Aquamarine, Koi, Pineapple, Redwood]
Key key = new Key(listNamespace, listSet, theKey);
Record origRecord = client.get(null, key);
System.out.println("Unsorted – " + origRecord.getValue(listIntBinName));
origRecord = client.operate(client.writePolicyDefault, key,
ListOperation.sort(listIntBinName, ListSortFlags.DEFAULT)
);
Record finalRecord = client.get(null, key);
System.out.println(" Sorted – " + finalRecord.getValue(listIntBinName));
Unsorted – [81, 3, 27, 120, 27, 1, 17] Sorted – [1, 3, 17, 27, 27, 81, 120]
Truncate the set from the Aerospike Database.
import com.aerospike.client.policy.InfoPolicy;
InfoPolicy infoPolicy = new InfoPolicy();
client.truncate(infoPolicy, listNamespace, listSet, null);
System.out.println("Set truncated.");
Set truncated.
client.close();
System.out.println("Server connection closed.");
Server connection closed.
Here is a collection of all of the non-Jupyter code from this tutorial.
// Import Java Libraries.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
// Import Aerospike Client Libraries.
import com.aerospike.client.AerospikeClient;
import com.aerospike.client.Key;
import com.aerospike.client.Bin;
import com.aerospike.client.policy.ClientPolicy;
import com.aerospike.client.Record;
import com.aerospike.client.Operation;
import com.aerospike.client.Value;
import com.aerospike.client.cdt.ListOperation;
import com.aerospike.client.cdt.ListReturnType;
import com.aerospike.client.cdt.ListSortFlags;
import com.aerospike.client.policy.InfoPolicy;
// Start the Aerospike Client.
AerospikeClient client = new AerospikeClient("localhost", 3000);
System.out.println("Initialized the client and connected to the cluster.");
// Create Test Data.
ArrayList<String> listStr = new ArrayList<String>();
listStr.add("Annette");
listStr.add("Redwood");
listStr.add("Aquamarine");
listStr.add("Pineapple");
System.out.println("Created String List: " + listStr);
ArrayList<Integer> listInt = new ArrayList<Integer>();
listInt.add(81);
listInt.add(3);
listInt.add(27);
listInt.add(9);
listInt.add(27);
listInt.add(1);
System.out.println("Created Integer List: " + listInt);
// Put Record into Aerospike.
String listSet = "listset1";
String listNamespace = "test";
String listStrBinName = "liststrbin";
String listIntBinName = "listintbin";
ClientPolicy clientPolicy = new ClientPolicy();
InfoPolicy infoPolicy = new InfoPolicy();
Integer theKey = 0;
Key key = new Key(listNamespace, listSet, theKey);
Bin bin1 = new Bin(listStrBinName, listStr);
Bin bin2 = new Bin(listIntBinName, listInt);
client.put(clientPolicy.writePolicyDefault, key, bin1, bin2);
System.out.println("Inserted Key: " + theKey + ", " + listStrBinName + ": " + listStr + ", " + listIntBinName + ": " + listInt);
// Get Data from Aerospike.
// 1. Get Record.
// 2. Get the Last String and Highest Rank.
// 3. Get Integers Between 3 and 27.
// 4. Get 2 Integers By Rank Starting with the Second Rank Item.
int last = -1;
int highestRank = -1;
int lowerBound = 3;
int upperBound = 27;
int secondRank = 1;
int rangeRankSize = 2;
Key key = new Key(listNamespace, listSet, theKey);
Record record = client.get(null, key);
Record postOp = client.operate(client.writePolicyDefault, key,
ListOperation.get(listStrBinName, last),
ListOperation.getByRank(listStrBinName, highestRank, ListReturnType.VALUE),
ListOperation.getByValueRange(listIntBinName, Value.get(lowerBound), Value.get(upperBound),
ListReturnType.VALUE),
ListOperation.getByRankRange(listIntBinName, secondRank, rangeRankSize, ListReturnType.VALUE)
);
List<?> returnStr = postOp.getList(listStrBinName);
List<?> returnIntList = postOp.getList(listIntBinName);
System.out.println("Read the Full Record From Aerospike:" + record);
System.out.println("The last string: " + returnStr.get(0));
System.out.println("The highest rank string: " + returnStr.get(1));
System.out.println("The integers between " + lowerBound + " and " + upperBound + ": "
+ returnIntList.get(0));
System.out.println("The 2nd and 3rd ranked integers: " + returnIntList.get(1));
// Update the Record in Aerospike
// 1. Add Koi twice to the String List.
// 2. Remove the Name from the String List.
// 3. Append 17 to the Integer List.
// 4. Increment the 4th Integer by 111.
// 5. Sort the Strings and Drop Duplicates.
// 6. Sort the Integers and Keep Duplicates.
String Fish = "Koi";
int fishIndex0 = 1;
int fishIndex1 = -1;
int nameIndex = 0;
int seventeen = 17;
int incNum = 111;
int incIndex = 3;
origRecord = client.operate(client.writePolicyDefault, key,
ListOperation.insert(listStrBinName, fishIndex0, Value.get(Fish)),
ListOperation.insert(listStrBinName, fishIndex1, Value.get(Fish)),
ListOperation.remove(listStrBinName, nameIndex),
ListOperation.append(listIntBinName, Value.get(seventeen)),
ListOperation.increment(listIntBinName, incIndex, Value.get(incNum)),
ListOperation.sort(listStrBinName, ListSortFlags.DROP_DUPLICATES),
ListOperation.sort(listIntBinName, ListSortFlags.DEFAULT)
);
List<?> opStrResults = origRecord.getList(listStrBinName);
List<?> opIntResults = origRecord.getList(listIntBinName);
Record finalRecord = client.get(null, key);
System.out.println("Inserted " + Fish + "; " + listStrBinName + " size is now: " + opStrResults.get(0));
System.out.println("Inserted " + Fish + "; " + listStrBinName + " size is now: " + opStrResults.get(1));
System.out.println("Removed item at index " + nameIndex + "; removed " + opStrResults.get(2) + " item");
System.out.println("Appended " + seventeen + ", " + listIntBinName + " size is now " + opIntResults.get(0));
System.out.println("Incremented item at index " + incIndex + " by " + incNum + "; new value is: " + opIntResults.get(1));
System.out.println("Sorted both lists and removed duplicates in " + listStrBinName);
System.out.println("After Record Edits – " + finalRecord);
// Truncate the Set.
client.truncate(infoPolicy, listNamespace, listSet, null);
System.out.println("Set truncated.");
// Close the Client Connections.
client.close();
System.out.println("Closed client connections.");
Initialized the client and connected to the cluster. Created String List: [Annette, Redwood, Aquamarine, Pineapple] Created Integer List: [81, 3, 27, 9, 27, 1] Inserted Key: 0, liststrbin: [Annette, Redwood, Aquamarine, Pineapple], listintbin: [81, 3, 27, 9, 27, 1] Read the Full Record From Aerospike:(gen:1),(exp:359404610),(bins:(liststrbin:[Annette, Redwood, Aquamarine, Pineapple]),(listintbin:[81, 3, 27, 9, 27, 1])) The last string: Pineapple The highest rank string: Redwood The integers between 3 and 27: [3, 9] The 2nd and 3rd ranked integers: [9, 3] Inserted Koi; liststrbin size is now: 5 Inserted Koi; liststrbin size is now: 6 Removed item at index 0; removed 1 item Appended 17, listintbin size is now 7 Incremented item at index 3 by 111; new value is: 120 Sorted both lists and removed duplicates in liststrbin After Record Edits – (gen:2),(exp:359404610),(bins:(liststrbin:[Aquamarine, Koi, Pineapple, Redwood]),(listintbin:[1, 3, 17, 27, 27, 81, 120])) Set truncated. Closed client connections.
Aerospike and its Java Client are up to the task of working with your list data. APIs contain rich operations to read and update list data using index, value, and rank.
Have questions? Don't hesitate to reach out if you have additional questions about working with lists at https://discuss.aerospike.com/.
Want to learn about modeling using Lists? See, Modeling Using Lists.
Want to check out other Java notebooks?
Are you running this from Binder? Download the Aerospike Notebook Repo and work with Aerospike Database and Jupyter locally using a Docker container.