Skip to main content

Modeling Using Lists

For an interactive Jupyter notebook experience: Binder

Last updated: June 22, 2021

Given that each record in Aerospike adds 64 bytes to the index, the intuition is to store maps and lists of data – documents of data – rather than individual values.

In particular, a List represents a lightweight record structure that optimizes storage, and Aerospike's List Operations provide an intuitive set of tools to work with document-oriented data. This notebook shares how Aerospike facilitates working with list data, covering the following topics:

  • Ordering
  • Value Comparisons
  • Intervals
  • Relative Range Rank

The above Aerospike capabilities provide significant utility through sorting and ordering lists. This notebook shares how to use lists as a powerful modeling tool and incorporating these strengths.

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.

Notebook Setup

Import Jupyter Java Integration

import io.github.spencerpark.ijava.IJava;
import io.github.spencerpark.jupyter.kernel.magic.common.Shell;

IJava.getKernelInstance().getMagics().registerMagics(Shell.class);

Start Aerospike

%sh asd

Download the Aerospike Java Client

%%loadFromPOM
<dependencies>
<dependency>
<groupId>com.aerospike</groupId>
<artifactId>aerospike-client</artifactId>
<version>5.0.0</version>
</dependency>
</dependencies>

Start the Aerospike Java Client and Connect

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.");

Output:

Initialized the client and connected to the cluster.

Unordered Data – Lists Preserve Insertion Order

Putting data into an Aerospike unordered list preserves the original order. This order can be accessed by index operations, and is maintained by adding new data using the append operation. Using the insert operation to add at an index, inserts before a preexisting list element, and increments the index for the preexisting element and subsequent elements.

For more information on list operations, go here.

For more information on map operations, go here.

Ordered Data – Lists Preserve Rank Order

The best practice for ordering a bin is to order it upon creation in Aerospike. When there are few or no items in the list, the computational cost of ordering the bin is smallest.

List order can be set at any time using the setOrder list operation.

To put data into an ordered list, use append. Append automatically reorders list elements by rank. Because list order is automatically maintained, Aerospike users cannot use insert to place elements into a specific index in an ordered list.

Performance Implications of Ordering a List

When working with real time data at scale, performance is everything and each operation has a performance cost. For List operations, Aerospike provides performance analysis for all operations. Because Aerospike was made for real-time data processing of extremely large datasets, analysis is provided in Big O notation. All performance estimates are worst-case and not average or best-case numbers.

Storing ordered data has its cost and benefits at scale:

  • An application that has few writes and many reads that use list order can benefit significantly from using server cycles to order data.
  • An application that has few reads and many writes can benefit significantly from using an unordered list.

Use these estimates when considering how to optimize Aerospike for a particular use case, and not as a comparison to other data products. All of the following factors contribute to overall data product performance:

  1. Network time from the client to the server.
  2. Time to pick the command from the network card.
  3. Time to fetch the object from storage or locate and access it in memory.
  4. Time complexity of performing the operation.
  5. Time to send the result back to the client over the network

Example – Creating Ordered and Unordered Lists

Create a Single Element List [1]

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

ArrayList<Integer> origListInt = new ArrayList<Integer>();
origListInt.add(1);

System.out.println("Original Integer List: " + origListInt);

Output:

Original Integer List: [1]

Put The List Into Two Bins

import com.aerospike.client.Key;
import com.aerospike.client.Bin;
import com.aerospike.client.policy.ClientPolicy;

Integer theKey = 0;
String listModelSet = "listmodelset";
String listModelNamespace = "test";
String orderedBinName = "ordered";
String unorderedBinName = "unordered";
ClientPolicy clientPolicy = new ClientPolicy();

Key key = new Key(listModelNamespace, listModelSet, theKey);
Bin bin1 = new Bin(orderedBinName, origListInt);
Bin bin2 = new Bin(unorderedBinName, origListInt);

client.put(clientPolicy.writePolicyDefault, key, bin1, bin2);
System.out.println("Put list into record with bins: " + orderedBinName + " and "
+ unorderedBinName);

Output:

Put list into record with bins: ordered and unordered

Set the Sort Order for the Ordered Bin

The default order applied to a bin is unordered.

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.ListOrder;

Record record = client.get(null, key);
record = client.operate(client.writePolicyDefault, key,
ListOperation.setOrder(orderedBinName, ListOrder.ORDERED)
);

System.out.println("Configured ordering policy for bin: " + orderedBinName);

Output:

Configured ordering policy for bin: ordered

Append Elements to Both Bins

Append additional elements [4, 7, 3, 9, 26, 11]

ArrayList<Value> addListInt = new ArrayList<Value>();
addListInt.add(Value.get(4));
addListInt.add(Value.get(7));
addListInt.add(Value.get(3));
addListInt.add(Value.get(9));
addListInt.add(Value.get(26));
addListInt.add(Value.get(11));

System.out.println("Appending the following list items to both lists: " + addListInt);

Record record = client.get(null, key);
record = client.operate(client.writePolicyDefault, key,
ListOperation.appendItems(orderedBinName, addListInt),
ListOperation.appendItems(unorderedBinName, addListInt)
);

Record finalListComp = client.get(null, key);
System.out.println("The Unordered List is " + finalListComp.getValue(unorderedBinName));
System.out.println("The Ordered List is " + finalListComp.getValue(orderedBinName));

Output:

Appending the following list items to both lists: [4, 7, 3, 9, 26, 11]
The Unordered List is [1, 4, 7, 3, 9, 26, 11]
The Ordered List is [1, 3, 4, 7, 9, 11, 26]

Rank Operations Provide JIT Ordering for Unordered Lists

Regardless of the architectural choice to store data in an ordered or unordered list, Aerospike provides data using the Rank operation in an intuitive order, as described below.

For an ordered list, Aerospike updates the list rank order with each addition. When using an unordered list, Aerospike calculates the same list rank just-in-time.

Rank Order for All Data Types

Because an Aerospike list can contain different data types, including nesting lists or maps within a list. Aerospike groups elements into like-types with the following relative ranks:

  1. NIL

  2. Boolean (Reserved for the future.)

  3. Integer

  4. String

  5. List

  6. Map

  7. Bytes

  8. Double

  9. GeoJSON

  10. INF

For more information on the order of data types, go

here.

NIL and INF are useful singletons for comparison purposes. NIL is a valid List and Map value, but is not a valid Bin value. To empty a Bin, assign NIL to it.

WILDCARD is not an ordinal like NIL and INF. As its name suggests, it is a useful singleton for List comparison purposes that matches everything.

Within like-type groups, each element is also ordered by rank. The following example demonstrates the rank operation.

Using Rank Operations on Lists

Create A Mixed Data Type List

Create a list containing characters, integers, and a nested list:

['c', 3, 26, [25, 'y', 1], 11, 9, 4, 'a', 1, 7]

ArrayList<Value> subMixedList = new ArrayList<Value>();
subMixedList.add(Value.get(25));
subMixedList.add(Value.get("y"));
subMixedList.add(Value.get(1));

System.out.println("Sub Mixed Type List: " + subMixedList);

ArrayList<Value> mixedDataList = new ArrayList<Value>();
mixedDataList.add(Value.get("c"));
mixedDataList.add(Value.get(3));
mixedDataList.add(Value.get(26));
mixedDataList.add(Value.get(subMixedList));
mixedDataList.add(Value.get(11));
mixedDataList.add(Value.get(9));
mixedDataList.add(Value.get(4));
mixedDataList.add(Value.get("a"));
mixedDataList.add(Value.get(1));
mixedDataList.add(Value.get(7));

System.out.println("Mixed Type Data List: " + mixedDataList);

Output:

Sub Mixed Type List: [25, y, 1]
Mixed Type Data List: [c, 3, 26, [25, y, 1], 11, 9, 4, a, 1, 7]

Put the List into Ordered and Unordered Bins

Integer mixedKey = 1;

Key key = new Key(listModelNamespace, listModelSet, mixedKey);
Bin bin1 = new Bin(orderedBinName, mixedDataList);
Bin bin2 = new Bin(unorderedBinName, mixedDataList);

client.put(clientPolicy.writePolicyDefault, key, bin1, bin2);
System.out.println("Created record with bins: " + orderedBinName + " and "
+ unorderedBinName);

Output:

Created record with bins: ordered and unordered

Set the Sort Order for the Ordered Bin

Record record = client.get(null, key);
record = client.operate(client.writePolicyDefault, key,
ListOperation.setOrder(orderedBinName, ListOrder.ORDERED)
);
Record finalListComp = client.get(null, key);

System.out.println("Configured ordering policy for bin: " + orderedBinName);
System.out.println("The Unordered List is " + finalListComp.getValue(unorderedBinName));
System.out.println("The Ordered List is " + finalListComp.getValue(orderedBinName));

Output:

Configured ordering policy for bin: ordered
The Unordered List is [c, 3, 26, [25, y, 1], 11, 9, 4, a, 1, 7]
The Ordered List is [1, 3, 4, 7, 9, 11, 26, a, c, [25, y, 1]]

What is the range of elements between NIL and 10?

When comparing ranges in Aerospike, the lower end is inclusive, and the upper end is exclusive

The singleton NIL is accessed in Java as Value.NULL. For more information on Values, go here.

import com.aerospike.client.cdt.ListReturnType;

Value lowEnd = Value.NULL;
Value highEnd = Value.get(10);

Record rangeNIL10 = client.get(null, key);
rangeNIL10 = client.operate(client.writePolicyDefault, key,
ListOperation.getByValueRange(orderedBinName, lowEnd, highEnd,
ListReturnType.VALUE),
ListOperation.getByValueRange(unorderedBinName, lowEnd, highEnd,
ListReturnType.VALUE)
);

System.out.println("The Unordered List range is " + rangeNIL10.getValue(unorderedBinName));
System.out.println("The Ordered List range is " + rangeNIL10.getValue(orderedBinName));

Output:

The Unordered List range is [3, 9, 4, 1, 7]
The Ordered List range is [1, 3, 4, 7, 9]

What is the range of elements between 'a' and [ ]?

ArrayList<Value> emptyList = new ArrayList<Value>();

Value lowEnd = Value.get("a");
Value highEnd = Value.get(emptyList);

Record rangeANullList = client.get(null, key);
rangeANullList = client.operate(client.writePolicyDefault, key,
ListOperation.getByValueRange(orderedBinName, lowEnd, highEnd,
ListReturnType.VALUE),
ListOperation.getByValueRange(unorderedBinName, lowEnd, highEnd,
ListReturnType.VALUE)
);

System.out.println("The Unordered List range is " + rangeANullList.getValue(unorderedBinName));
System.out.println("The Ordered List range is " + rangeANullList.getValue(orderedBinName));

Output:

The Unordered List range is [c, a]
The Ordered List range is [a, c]

What is the range of elements between [ ] and INF?

The singleton INF, a clean upper bound for rank comparisons, is accessed in Java as Value.INFINITY. For more information on Values, go here.

Value lowEnd = Value.get(emptyList);
Value highEnd = Value.INFINITY;

Record rangeNullInf = client.get(null, key);
rangeNullInf = client.operate(client.writePolicyDefault, key,
ListOperation.getByValueRange(orderedBinName, lowEnd, highEnd,
ListReturnType.VALUE),
ListOperation.getByValueRange(unorderedBinName, lowEnd, highEnd,
ListReturnType.VALUE)
);

System.out.println("The Unordered List range is " + rangeNullInf.getValue(unorderedBinName));
System.out.println("The Ordered List range is " + rangeNullInf.getValue(orderedBinName));

Output:

The Unordered List range is [[25, y, 1]]
The Ordered List range is [[25, y, 1]]

Rank Works Reliably Independent of List Ordering

As demonstrated above, rank works identically, no matter whether the list is ordered or not.

Using Rank on Lists of Tuples

Ordering lists containing sub-lists and nested maps works intuitively and differently from simple lists.

  1. Sub-lists or maps in an ordered list are not implicitly ordered.
  2. Items are inserted in rank order.
  3. Greater List length results in higher rank

Here are some examples.

Create a Sorted and Unsorted Empty List

Integer listOfListsKey = 2;

Key key = new Key(listModelNamespace, listModelSet, listOfListsKey);
Bin bin1 = new Bin(orderedBinName, emptyList);
Bin bin2 = new Bin(unorderedBinName, emptyList);

client.put(clientPolicy.writePolicyDefault, key, bin1, bin2);
System.out.println("Created record with bins: " + orderedBinName + " and "
+ unorderedBinName);

Record record = client.get(null, key);
record = client.operate(client.writePolicyDefault, key,
ListOperation.setOrder(orderedBinName, ListOrder.ORDERED)
);
Record initialEmptyLists = client.get(null, key);

System.out.println("Configured ordering policy to bin: " + orderedBinName);
System.out.println("The Unordered List is " + initialEmptyLists.getValue(unorderedBinName));
System.out.println("The Ordered List is " + initialEmptyLists.getValue(orderedBinName));

Output:

Created record with bins: ordered and unordered
Configured ordering policy to bin: ordered
The Unordered List is []
The Ordered List is []

Add the tuple [1, 1]

ArrayList<Integer> thisTuple = new ArrayList<Integer>();
thisTuple.add(1);
thisTuple.add(1);

Record record = client.get(null, key);
record = client.operate(client.writePolicyDefault, key,
ListOperation.append(orderedBinName, Value.get(thisTuple)),
ListOperation.append(unorderedBinName, Value.get(thisTuple))
);
Record listWith11 = client.get(null, key);

System.out.println("The Unordered List is " + listWith11.getValue(unorderedBinName));
System.out.println("The Ordered List is " + listWith11.getValue(orderedBinName));

Output:

The Unordered List is [[1, 1]]
The Ordered List is [[1, 1]]

Add the tuple [1, 3]

ArrayList<Integer> thisTuple = new ArrayList<Integer>();
thisTuple.add(1);
thisTuple.add(3);

Record record = client.get(null, key);
record = client.operate(client.writePolicyDefault, key,
ListOperation.append(orderedBinName, Value.get(thisTuple)),
ListOperation.append(unorderedBinName, Value.get(thisTuple))
);
Record listWith13 = client.get(null, key);

System.out.println("The Unordered List is " + listWith13.getValue(unorderedBinName));
System.out.println("The Ordered List is " + listWith13.getValue(orderedBinName));

Output:

The Unordered List is [[1, 1], [1, 3]]
The Ordered List is [[1, 1], [1, 3]]

Add the tuple [1, 2, 0, 1]

ArrayList<Integer> thisTuple = new ArrayList<Integer>();
thisTuple.add(1);
thisTuple.add(2);
thisTuple.add(0);
thisTuple.add(1);

Record record = client.get(null, key);
record = client.operate(client.writePolicyDefault, key,
ListOperation.append(orderedBinName, Value.get(thisTuple)),
ListOperation.append(unorderedBinName, Value.get(thisTuple))
);
Record listWith1201 = client.get(null, key);

System.out.println("The Unordered List is " + listWith1201.getValue(unorderedBinName));
System.out.println("The Ordered List is " + listWith1201.getValue(orderedBinName));

Output:

The Unordered List is [[1, 1], [1, 3], [1, 2, 0, 1]]
The Ordered List is [[1, 1], [1, 2, 0, 1], [1, 3]]

Add the tuple [1, 2]

ArrayList<Integer> thisTuple = new ArrayList<Integer>();
thisTuple.add(1);
thisTuple.add(2);

Record record = client.get(null, key);
record = client.operate(client.writePolicyDefault, key,
ListOperation.append(orderedBinName, Value.get(thisTuple)),
ListOperation.append(unorderedBinName, Value.get(thisTuple))
);
Record listWith12 = client.get(null, key);

System.out.println("The Unordered List is " + listWith12.getValue(unorderedBinName));
System.out.println("The Ordered List is " + listWith12.getValue(orderedBinName));

Output:

The Unordered List is [[1, 1], [1, 3], [1, 2, 0, 1], [1, 2]]
The Ordered List is [[1, 1], [1, 2], [1, 2, 0, 1], [1, 3]]

Using Intervals

Interval operations return all list elements in the range between a given lower and upper bound, whether or not the list is ordered. An unordered list will JIT sort. Intervals use the same consistent rank order across data types:

  • [2, NIL] is defined as after anything [1, ...], regardless of element count.
  • [1, INF] is defined as after anything [1, ...] and before anything [2, ...].

Intervals serve as a query that allows for a list to be used as a tuple, a lightweight record structure without key names.

Here are some examples:

Create a List of Tuples

[[2, 7], [3, 1], [1, 1], [2, 5], [1, 2], [0, 3]]

ArrayList<Integer> subTuple0 = new ArrayList<Integer>();
subTuple0.add(2);
subTuple0.add(7);

ArrayList<Integer> subTuple1 = new ArrayList<Integer>();
subTuple1.add(3);
subTuple1.add(1);

ArrayList<Integer> subTuple2 = new ArrayList<Integer>();
subTuple2.add(1);
subTuple2.add(1);

ArrayList<Integer> subTuple3 = new ArrayList<Integer>();
subTuple3.add(2);
subTuple3.add(5);

ArrayList<Integer> subTuple4 = new ArrayList<Integer>();
subTuple4.add(1);
subTuple4.add(2);

ArrayList<Integer> subTuple5 = new ArrayList<Integer>();
subTuple5.add(0);
subTuple5.add(3);

ArrayList<Value> tupleList = new ArrayList<Value>();
tupleList.add(Value.get(subTuple0));
tupleList.add(Value.get(subTuple1));
tupleList.add(Value.get(subTuple2));
tupleList.add(Value.get(subTuple3));
tupleList.add(Value.get(subTuple4));
tupleList.add(Value.get(subTuple5));

System.out.println("Tuple List: " + tupleList);

Output:

Tuple List: [[2, 7], [3, 1], [1, 1], [2, 5], [1, 2], [0, 3]]

Put the List Into Two Aerospike Bins

Integer tupleKey = 3;

Key key = new Key(listModelNamespace, listModelSet, tupleKey);
Bin bin1 = new Bin(orderedBinName, tupleList);
Bin bin2 = new Bin(unorderedBinName, tupleList);

client.put(clientPolicy.writePolicyDefault, key, bin1, bin2);
System.out.println("Created record with bins: " + orderedBinName + " and "
+ unorderedBinName);

Output:

Created record with bins: ordered and unordered

Set the Sort Order for the Ordered Bin

Record record = client.get(null, key);
record = client.operate(client.writePolicyDefault, key,
ListOperation.setOrder(orderedBinName, ListOrder.ORDERED)
);
Record initialEmptyLists = client.get(null, key);

System.out.println("Configured ordering policy for bin: " + orderedBinName);

Output:

Configured ordering policy for bin: ordered

Get the Interval Between [1, NIL] and [2, NIL]

ArrayList<Value> lowTuple = new ArrayList<Value>();
lowTuple.add(Value.get(1));
lowTuple.add(Value.NULL);

ArrayList<Value> highTuple = new ArrayList<Value>();
highTuple.add(Value.get(2));
highTuple.add(Value.NULL);

Record between1and2 = client.get(null, key);
between1and2 = client.operate(client.writePolicyDefault, key,
ListOperation.getByValueRange(orderedBinName, Value.get(lowTuple), Value.get(highTuple),
ListReturnType.VALUE),
ListOperation.getByValueRange(unorderedBinName, Value.get(lowTuple), Value.get(highTuple),
ListReturnType.VALUE)
);

System.out.println("The Unordered List between " + lowTuple + " and " + highTuple + " is "
+ between1and2.getValue(unorderedBinName));
System.out.println("The Ordered List between " + lowTuple + " and " + highTuple + " is "
+ between1and2.getValue(orderedBinName));

Output:

The Unordered List between [1, null] and [2, null] is [[1, 1], [1, 2]]
The Ordered List between [1, null] and [2, null] is [[1, 1], [1, 2]]

Get the Interval Between [1, NIL] and [1, INF].

ArrayList<Value> lowTuple = new ArrayList<Value>();
lowTuple.add(Value.get(1));
lowTuple.add(Value.NULL);

ArrayList<Value> highTuple = new ArrayList<Value>();
highTuple.add(Value.get(1));
highTuple.add(Value.INFINITY);

Record between1NILand1INF = client.get(null, key);
between1NILand1INF = client.operate(client.writePolicyDefault, key,
ListOperation.getByValueRange(orderedBinName, Value.get(lowTuple), Value.get(highTuple),
ListReturnType.VALUE),
ListOperation.getByValueRange(unorderedBinName, Value.get(lowTuple), Value.get(highTuple),
ListReturnType.VALUE)
);

System.out.println("The Unordered List between " + lowTuple + " and " + highTuple + " is "
+ between1NILand1INF.getValue(unorderedBinName));
System.out.println("The Ordered List between " + lowTuple + " and " + highTuple + " is "
+ between1NILand1INF.getValue(orderedBinName));

Output:

The Unordered List between [1, null] and [1, INF] is [[1, 1], [1, 2]]
The Ordered List between [1, null] and [1, INF] is [[1, 1], [1, 2]]

The Results are Independent of List Order

As demonstrated, the results are the same whether the data is ordered or unordered in the database.

Examples

Example 1 – IoT Model

Modeling with tuples is powerful. Consider a smart thermometer taking a reading one time per minute. This use case can be modeled as a list of tuples.

For more information on this IoT example, go here.

Create Sample Data

Record Format – [minutes-since-epoch, temperature] [14062, 39.04] [14063, 39.78] [14065, 40.07] [14064, 40.89] [14066, 41.18] [14067, 40.93]

ArrayList<Value> subTuple0 = new ArrayList<Value>();
subTuple0.add(Value.get(14062));
subTuple0.add(Value.get(39.04));

ArrayList<Value> subTuple1 = new ArrayList<Value>();
subTuple1.add(Value.get(14063));
subTuple1.add(Value.get(39.78));

ArrayList<Value> subTuple2 = new ArrayList<Value>();
subTuple2.add(Value.get(14065));
subTuple2.add(Value.get(40.07));

ArrayList<Value> subTuple3 = new ArrayList<Value>();
subTuple3.add(Value.get(14064));
subTuple3.add(Value.get(40.89));

ArrayList<Value> subTuple4 = new ArrayList<Value>();
subTuple4.add(Value.get(14066));
subTuple4.add(Value.get(41.18));

ArrayList<Value> subTuple5 = new ArrayList<Value>();
subTuple5.add(Value.get(14067));
subTuple5.add(Value.get(40.93));

ArrayList<Value> tupleListIoT = new ArrayList<Value>();
tupleListIoT.add(Value.get(subTuple0));
tupleListIoT.add(Value.get(subTuple1));
tupleListIoT.add(Value.get(subTuple2));
tupleListIoT.add(Value.get(subTuple3));
tupleListIoT.add(Value.get(subTuple4));
tupleListIoT.add(Value.get(subTuple5));

System.out.println("IoT Tuple List: " + tupleListIoT);

Output:

IoT Tuple List: [[14062, 39.04], [14063, 39.78], [14065, 40.07], [14064, 40.89], [14066, 41.18], [14067, 40.93]]

Put the List in an Unordered Bin

Integer keyIoT = 4;
ClientPolicy clientPolicy = new ClientPolicy();

Key key = new Key(listModelNamespace, listModelSet, keyIoT);
Bin bin1 = new Bin(unorderedBinName, tupleListIoT);

client.put(clientPolicy.writePolicyDefault, key, bin1);
System.out.println("Created record with bin: " + unorderedBinName);

Output:

Created record with bin: unordered

Get Temperature Readings Between Minute 14063 and 14064

ArrayList<Value> lowTuple = new ArrayList<Value>();
lowTuple.add(Value.get(14063));
lowTuple.add(Value.NULL);

ArrayList<Value> highTuple = new ArrayList<Value>();
highTuple.add(Value.get(14064));
highTuple.add(Value.INFINITY);

Record between14063and14064 = client.get(null, key);
between14063and14064 = client.operate(client.writePolicyDefault, key,
ListOperation.getByValueRange(unorderedBinName, Value.get(lowTuple), Value.get(highTuple),
ListReturnType.VALUE)
);

System.out.println("The readings between " + lowTuple + " and " + highTuple + " are "
+ between14063and14064.getValue(unorderedBinName));

Output:

The readings between [14063, null] and [14064, INF] are [[14063, 39.78], [14064, 40.89]]

Example 2 – 100 Meter Sprint Leaderboard

Here is an example with mixed type data and overlapping datasets. It also highlights Aerospike's ability to find the tuples closest to a given value and relative range ranking.

Create Overlapping Mixed-Type Data Sample

Record format – [Time, Athlete, Location, Date]

Create Example Dataset 1

wr100m1 – [ [10.06, "Bob Hayes", "Tokyo, Japan", "October 15, 1964"], [10.03, "Jim Hines", "Sacramento, USA", "June 20, 1968"], [10.02, "Charles Greene", "Mexico City, Mexico", "October 13, 1968"], [9.95, "Jim Hines", "Mexico City, Mexico", "October 14, 1968"], [9.93, "Calvin Smith", "Colorado Springs, USA", "July 3, 1983"], [9.93, "Carl Lewis", "Rome, Italy", "August 30, 1987"], [9.92, "Carl Lewis", "Seoul, South Korea", "September 24, 1988"] ]

ArrayList<Value> wr100One0 = new ArrayList<Value>();
wr100One0.add(Value.get(10.06));
wr100One0.add(Value.get("Bob Hayes"));
wr100One0.add(Value.get("Tokyo, Japan"));
wr100One0.add(Value.get("October 15, 1964"));

ArrayList<Value> wr100One1 = new ArrayList<Value>();
wr100One1.add(Value.get(10.03));
wr100One1.add(Value.get("Jim Hines"));
wr100One1.add(Value.get("Sacramento, USA"));
wr100One1.add(Value.get("June 20,1968"));

ArrayList<Value> wr100One2 = new ArrayList<Value>();
wr100One2.add(Value.get(10.02));
wr100One2.add(Value.get("Charles Greene"));
wr100One2.add(Value.get("Mexico City, Mexico"));
wr100One2.add(Value.get("October 13, 1968"));

ArrayList<Value> wr100One3 = new ArrayList<Value>();
wr100One3.add(Value.get(9.95));
wr100One3.add(Value.get("Jim Hines"));
wr100One3.add(Value.get("Mexico City, Mexico"));
wr100One3.add(Value.get("October 14, 1968"));

ArrayList<Value> wr100One4 = new ArrayList<Value>();
wr100One4.add(Value.get(9.93));
wr100One4.add(Value.get("Calvin Smith"));
wr100One4.add(Value.get("Colorado Springs, USA"));
wr100One4.add(Value.get("July 3, 1983"));

ArrayList<Value> wr100One5 = new ArrayList<Value>();
wr100One5.add(Value.get(9.93));
wr100One5.add(Value.get("Carl Lewis"));
wr100One5.add(Value.get("Rome, Italy"));
wr100One5.add(Value.get("August 30, 1987"));

ArrayList<Value> wr100One6 = new ArrayList<Value>();
wr100One6.add(Value.get(9.92));
wr100One6.add(Value.get("Carl Lewis"));
wr100One6.add(Value.get("Seoul, South Korea"));
wr100One6.add(Value.get("September 24, 1988"));


ArrayList<Value> wr100m1List = new ArrayList<Value>();
wr100m1List.add(Value.get(wr100One0));
wr100m1List.add(Value.get(wr100One1));
wr100m1List.add(Value.get(wr100One2));
wr100m1List.add(Value.get(wr100One3));
wr100m1List.add(Value.get(wr100One4));
wr100m1List.add(Value.get(wr100One5));
wr100m1List.add(Value.get(wr100One6));


System.out.println("100m World Record Holder List 1: " + wr100m1List);

Output:

100m World Record Holder List 1: [[10.06, Bob Hayes, Tokyo, Japan, October 15, 1964], [10.03, Jim Hines, Sacramento, USA, June 20,1968], [10.02, Charles Greene, Mexico City, Mexico, October 13, 1968], [9.95, Jim Hines, Mexico City, Mexico, October 14, 1968], [9.93, Calvin Smith, Colorado Springs, USA, July 3, 1983], [9.93, Carl Lewis, Rome, Italy, August 30, 1987], [9.92, Carl Lewis, Seoul, South Korea, September 24, 1988]]

Create Example Dataset 2

wr_100m_2 – [ [9.93, "Carl Lewis", "Rome, Italy", "August 30, 1987"], [9.92, "Carl Lewis", "Seoul, South Korea", "September 24, 1988"], [9.90, "Leroy Burrell", "New York, USA", "June 14, 1991"], [9.86, "Carl Lewis", "Tokyo, Japan", "August 25, 1991"], [9.85, "Leroy Burrell", "Lausanne, Switzerland", "July 6, 1994"], [9.84, "Donovan Bailey", "Atlanta, USA", "July 27, 1996"], [9.79, "Maurice Greene", "Athens, Greece", "June 16, 1999"], [9.77, "Asafa Powell", "Athens, Greece", "June 14, 2005"], [9.77, "Asafa Powell", "Gateshead, England", "June 11, 2006"], [9.77, "Asafa Powell", "Zurich, Switzerland", "August 18, 2006"], [9.74, "Asafa Powell", "Rieti, Italy", "September 9, 2007"], [9.72, "Usain Bolt", "New York, USA", "May 31, 2008"], [9.69, "Usain Bolt", "Beijing, China", "August 16, 2008"], [9.58, "Usain Bolt", "Berlin, Germany", "August 16, 2009"] ]

ArrayList<Value> wr100Two0 = new ArrayList<Value>();
wr100Two0.add(Value.get(9.93));
wr100Two0.add(Value.get("Carl Lewis"));
wr100Two0.add(Value.get("Rome, Italy"));
wr100Two0.add(Value.get("August 30, 1987"));

ArrayList<Value> wr100Two1 = new ArrayList<Value>();
wr100Two1.add(Value.get(9.92));
wr100Two1.add(Value.get("Carl Lewis"));
wr100Two1.add(Value.get("Seoul, South Korea"));
wr100Two1.add(Value.get("September 24, 1988"));

ArrayList<Value> wr100Two2 = new ArrayList<Value>();
wr100Two2.add(Value.get(9.90));
wr100Two2.add(Value.get("Leroy Burrell"));
wr100Two2.add(Value.get("New York, USA"));
wr100Two2.add(Value.get("June 14, 1991"));

ArrayList<Value> wr100Two3 = new ArrayList<Value>();
wr100Two3.add(Value.get(9.86));
wr100Two3.add(Value.get("Carl Lewis"));
wr100Two3.add(Value.get("Tokyo, Japan"));
wr100Two3.add(Value.get("August 25, 1991"));

ArrayList<Value> wr100Two4 = new ArrayList<Value>();
wr100Two4.add(Value.get(9.85));
wr100Two4.add(Value.get("Leroy Burrell"));
wr100Two4.add(Value.get("Lausanne, Switzerland"));
wr100Two4.add(Value.get("July 6, 1994"));

ArrayList<Value> wr100Two5 = new ArrayList<Value>();
wr100Two5.add(Value.get(9.84));
wr100Two5.add(Value.get("Donovan Bailey"));
wr100Two5.add(Value.get("Atlanta, USA"));
wr100Two5.add(Value.get("July 27, 1996"));

ArrayList<Value> wr100Two6 = new ArrayList<Value>();
wr100Two6.add(Value.get(9.79));
wr100Two6.add(Value.get("Maurice Greene"));
wr100Two6.add(Value.get("Athens, Greece"));
wr100Two6.add(Value.get("June 16, 1999"));

ArrayList<Value> wr100Two7 = new ArrayList<Value>();
wr100Two7.add(Value.get(9.77));
wr100Two7.add(Value.get("Asafa Powell"));
wr100Two7.add(Value.get("Athens, Greece"));
wr100Two7.add(Value.get("June 14, 2005"));

ArrayList<Value> wr100Two8 = new ArrayList<Value>();
wr100Two8.add(Value.get(9.77));
wr100Two8.add(Value.get("Asafa Powell"));
wr100Two8.add(Value.get("Gateshead, England"));
wr100Two8.add(Value.get("June 11, 2006"));

ArrayList<Value> wr100Two9 = new ArrayList<Value>();
wr100Two9.add(Value.get(9.77));
wr100Two9.add(Value.get("Asafa Powell"));
wr100Two9.add(Value.get("Zurich, Switzerland"));
wr100Two9.add(Value.get("August 18, 2006"));

ArrayList<Value> wr100Two10 = new ArrayList<Value>();
wr100Two10.add(Value.get(9.74));
wr100Two10.add(Value.get("Asafa Powell"));
wr100Two10.add(Value.get("Rieti, Italy"));
wr100Two10.add(Value.get("September 9, 2007"));

ArrayList<Value> wr100Two11 = new ArrayList<Value>();
wr100Two11.add(Value.get(9.72));
wr100Two11.add(Value.get("Usain Bolt"));
wr100Two11.add(Value.get("New York, USA"));
wr100Two11.add(Value.get("May 31, 2008"));

ArrayList<Value> wr100Two12 = new ArrayList<Value>();
wr100Two12.add(Value.get(9.69));
wr100Two12.add(Value.get("Usain Bolt"));
wr100Two12.add(Value.get("Beijing, China"));
wr100Two12.add(Value.get("August 16, 2008"));

ArrayList<Value> wr100Two13 = new ArrayList<Value>();
wr100Two13.add(Value.get(9.58));
wr100Two13.add(Value.get("Usain Bolt"));
wr100Two13.add(Value.get("Berlin, Germany"));
wr100Two13.add(Value.get("August 16, 2009"));


ArrayList<Value> wr100m2List = new ArrayList<Value>();
wr100m2List.add(Value.get(wr100Two0));
wr100m2List.add(Value.get(wr100Two1));
wr100m2List.add(Value.get(wr100Two2));
wr100m2List.add(Value.get(wr100Two3));
wr100m2List.add(Value.get(wr100Two4));
wr100m2List.add(Value.get(wr100Two5));
wr100m2List.add(Value.get(wr100Two6));
wr100m2List.add(Value.get(wr100Two7));
wr100m2List.add(Value.get(wr100Two8));
wr100m2List.add(Value.get(wr100Two9));
wr100m2List.add(Value.get(wr100Two10));
wr100m2List.add(Value.get(wr100Two11));
wr100m2List.add(Value.get(wr100Two12));
wr100m2List.add(Value.get(wr100Two13));

System.out.println("100m World Record Holder List 2: " + wr100m2List);

Output:

100m World Record Holder List 2: [[9.93, Carl Lewis, Rome, Italy, August 30, 1987], [9.92, Carl Lewis, Seoul, South Korea, September 24, 1988], [9.9, Leroy Burrell, New York, USA, June 14, 1991], [9.86, Carl Lewis, Tokyo, Japan, August 25, 1991], [9.85, Leroy Burrell, Lausanne, Switzerland, July 6, 1994], [9.84, Donovan Bailey, Atlanta, USA, July 27, 1996], [9.79, Maurice Greene, Athens, Greece, June 16, 1999], [9.77, Asafa Powell, Athens, Greece, June 14, 2005], [9.77, Asafa Powell, Gateshead, England, June 11, 2006], [9.77, Asafa Powell, Zurich, Switzerland, August 18, 2006], [9.74, Asafa Powell, Rieti, Italy, September 9, 2007], [9.72, Usain Bolt, New York, USA, May 31, 2008], [9.69, Usain Bolt, Beijing, China, August 16, 2008], [9.58, Usain Bolt, Berlin, Germany, August 16, 2009]]

Put Dataset 1 Into An Aerospike Bin

Dataset 2 will be used later.

Integer keyWR = 5;
String listLeadersBinName = "leaders";

Key key = new Key(listModelNamespace, listModelSet, keyWR);
Bin bin1 = new Bin(listLeadersBinName, wr100m1List);

client.put(clientPolicy.writePolicyDefault, key, bin1);
System.out.println("Created record with bin: " + listLeadersBinName);

Output:

Created record with bin: leaders

Set the Sort Order for the Ordered Bin

Record record = client.get(null, key);
record = client.operate(client.writePolicyDefault, key,
ListOperation.setOrder(listLeadersBinName, ListOrder.ORDERED)
);

System.out.println("Configured ordering policy for bin: " + listLeadersBinName);

Output:

Configured ordering policy for bin: leaders

Find the Closest Matches to 10.0 Seconds using Relative Range Rank

Sometimes the goal is to find the closest matches to a given data point. Aerospike provides this using Relative Range Rank. This example finds the elements ranked before and after the value [10.0, NIL].

ArrayList<Value> searchTuple = new ArrayList<Value>();
searchTuple.add(Value.get(10.0));
searchTuple.add(Value.NULL);

Integer searchRank = -1;
Integer searchQty = 2;

Record closestTo10 = client.get(null, key);
closestTo10 = client.operate(client.writePolicyDefault, key,
ListOperation.getByValueRelativeRankRange(listLeadersBinName, Value.get(searchTuple),
searchRank, searchQty, ListReturnType.VALUE)
);

System.out.println("The Closest World Records to 10.0 seconds are " +
closestTo10.getValue(listLeadersBinName));

Output:

The Closest World Records to 10.0 seconds are [[9.95, Jim Hines, Mexico City, Mexico, October 14, 1968], [10.02, Charles Greene, Mexico City, Mexico, October 13, 1968]]

Combine the Two Lists into One Ordered List with Unique Elements

Create A List Policy to Remove Duplicates

A list write policy contains the sort order and flags to govern the addition. For information on the flags, go here.

Because the two Datasets contain overlapping records, the operation needs to apply the following policies:

  • ADD_UNIQUE – Add all unique items to the list.
  • NO_FAIL – Duplicate item errors are expected and should not cause the operation to fail.
  • PARTIAL – Add items that are not duplicates.
import com.aerospike.client.cdt.ListPolicy;
import com.aerospike.client.cdt.ListWriteFlags;

int listUniqueFlags = ListWriteFlags.ADD_UNIQUE
| ListWriteFlags.NO_FAIL
| ListWriteFlags.PARTIAL;

ListPolicy policyOrderedNoDupes = new ListPolicy(ListOrder.ORDERED, listUniqueFlags);

System.out.println("Created List Policy for Ordering and Adding Only Unique Items.");

Output:

Created List Policy for Ordering and Adding Only Unique Items.

Append the Second Dataset Using the New Policy

Record record = client.get(null, key);
record = client.operate(client.writePolicyDefault, key,
ListOperation.appendItems(policyOrderedNoDupes, listLeadersBinName, wr100m2List)
);
Record fullLeadersList = client.get(null, key);


System.out.println("The complete, deduplicated Leaders List is: "
+ fullLeadersList.getValue(listLeadersBinName));

Output:

The complete, deduplicated Leaders List is: [[9.58, Usain Bolt, Berlin, Germany, August 16, 2009], [9.69, Usain Bolt, Beijing, China, August 16, 2008], [9.72, Usain Bolt, New York, USA, May 31, 2008], [9.74, Asafa Powell, Rieti, Italy, September 9, 2007], [9.77, Asafa Powell, Athens, Greece, June 14, 2005], [9.77, Asafa Powell, Gateshead, England, June 11, 2006], [9.77, Asafa Powell, Zurich, Switzerland, August 18, 2006], [9.79, Maurice Greene, Athens, Greece, June 16, 1999], [9.84, Donovan Bailey, Atlanta, USA, July 27, 1996], [9.85, Leroy Burrell, Lausanne, Switzerland, July 6, 1994], [9.86, Carl Lewis, Tokyo, Japan, August 25, 1991], [9.9, Leroy Burrell, New York, USA, June 14, 1991], [9.92, Carl Lewis, Seoul, South Korea, September 24, 1988], [9.93, Calvin Smith, Colorado Springs, USA, July 3, 1983], [9.93, Carl Lewis, Rome, Italy, August 30, 1987], [9.95, Jim Hines, Mexico City, Mexico, October 14, 1968], [10.02, Charles Greene, Mexico City, Mexico, October 13, 1968], [10.03, Jim Hines, Sacramento, USA, June 20,1968], [10.06, Bob Hayes, Tokyo, Japan, October 15, 1964]]

Notebook Cleanup

Truncate the Set

Truncate the set from the Aerospike Database.

import com.aerospike.client.policy.InfoPolicy;
InfoPolicy infoPolicy = new InfoPolicy();

client.truncate(infoPolicy, listModelNamespace, listModelSet, null);
System.out.println("Set Truncated.");

Output:

Set Truncated.

Close the Connection to Aerospike

client.close();
System.out.println("Server connection closed.");

Output:

Server connection closed.

Code Summary

Here is a collection of all of the non-Jupyter code from this tutorial.

Overview

  1. Import Java Libraries.
  2. Import Aerospike Client Libraries.
  3. Start the Aerospike Client.
  4. Compare Sorted and Unsorted Integer Lists.
    1. Create Two Identical Lists.
    2. Sort One of the Lists.
    3. Add Elements to Both Lists.
  5. Apply Rank Operations on Sorted and Unsorted Mixed Data Type Lists.
    1. Create Two Identical Lists.
    2. Set the Sort Order for the Ordered List.
    3. Find the Range Between NIL and 10.
    4. Find the Range Between [ ] and INF.
  6. Apply Rank Operations on Nested Lists of Varying Length.
    1. Create Two Empty Lists.
    2. Sort One of the Lists.
    3. Put Lists of Varying Lengths in Both.
  7. Apply Interval Operations on Nested Lists.
    1. Create a List of Tuples.
    2. Put the List of Tuples in an Ordered and an Unordered Bin.
    3. Find the Interval between [1, NIL] and [2, NIL].
    4. Find the Interval between [1, NIL] and [1, INF].
  8. Example 1 – IoT Model.
    1. Create Sample Data.
    2. Find the Temperature between Minute 14063 and 14064.
  9. Example 2 – 100 Meter Leaderboard Model.
    1. Create Overlapping Datasets.
    2. Put the First Dataset in a Sorted Aerospike Bin
    3. Find the Closest World Record to 10.0 Seconds.
    4. Insert the Overlapping Dataset.
  10. Close the Client Connections.
// 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.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.ListOrder;
import com.aerospike.client.cdt.ListReturnType;
import com.aerospike.client.cdt.ListPolicy;
import com.aerospike.client.cdt.ListWriteFlags;
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.");
System.out.println();


// Compare Sorted and Unsorted Integer Lists.
// 1. Create Two Identical Lists.
// 2. Set the Sort Order for the Ordered List.
// 3. Add Elements to Both Lists.

ArrayList<Integer> origListInt = new ArrayList<Integer>();
origListInt.add(1);
ArrayList<Value> addListInt = new ArrayList<Value>();
addListInt.add(Value.get(4));
addListInt.add(Value.get(7));
addListInt.add(Value.get(3));
addListInt.add(Value.get(9));
addListInt.add(Value.get(26));
addListInt.add(Value.get(11));

Integer theKey = 0;
String listModelSet = "listmodelset";
String listModelNamespace = "test";
String orderedBinName = "ordered";
String unorderedBinName = "unordered";
ClientPolicy clientPolicy = new ClientPolicy();
InfoPolicy infoPolicy = new InfoPolicy();


Key key = new Key(listModelNamespace, listModelSet, theKey);
Bin bin1 = new Bin(orderedBinName, origListInt);
Bin bin2 = new Bin(unorderedBinName, origListInt);


client.put(clientPolicy.writePolicyDefault, key, bin1, bin2);
Record record = client.get(null, key);
record = client.operate(client.writePolicyDefault, key,
ListOperation.setOrder(orderedBinName, ListOrder.ORDERED),
ListOperation.appendItems(orderedBinName, addListInt),
ListOperation.appendItems(unorderedBinName, addListInt)
);
Record finalListComp = client.get(null, key);

System.out.println("Put list into record with bins: " + orderedBinName + " and "
+ unorderedBinName);
System.out.println("Original Integer List: " + origListInt);
System.out.println("Appending the following list items to both lists: " + addListInt);
System.out.println("The Unordered List is " + finalListComp.getValue(unorderedBinName));
System.out.println("The Ordered List is " + finalListComp.getValue(orderedBinName));
System.out.println();


// Apply Rank Operations on Sorted and Unsorted Mixed Data Type Lists
// 1. Create Two Identical Lists.
// 2. Set the Sort Order for the Ordered List.
// 3. Find the Range Between NIL and 10.
// 4. Find the Range Between [ ] and INF.

ArrayList<Value> subMixedList = new ArrayList<Value>();
subMixedList.add(Value.get(25));
subMixedList.add(Value.get("y"));
subMixedList.add(Value.get(1));

System.out.println("Sub Mixed Type List: " + subMixedList);

ArrayList<Value> mixedDataList = new ArrayList<Value>();
mixedDataList.add(Value.get("c"));
mixedDataList.add(Value.get(3));
mixedDataList.add(Value.get(26));
mixedDataList.add(Value.get(subMixedList));
mixedDataList.add(Value.get(11));
mixedDataList.add(Value.get(9));
mixedDataList.add(Value.get(4));
mixedDataList.add(Value.get("a"));
mixedDataList.add(Value.get(1));
mixedDataList.add(Value.get(7));

Value lowEnd0 = Value.NULL;
Value highEnd0 = Value.get(10);

ArrayList<Value> emptyList = new ArrayList<Value>();

Value lowEnd1 = Value.get("a");
Value highEnd1 = Value.get(emptyList);

Value lowEnd2 = Value.get(emptyList);
Value highEnd2 = Value.INFINITY;

Integer mixedKey = 1;

Key key = new Key(listModelNamespace, listModelSet, mixedKey);
Bin bin1 = new Bin(orderedBinName, mixedDataList);
Bin bin2 = new Bin(unorderedBinName, mixedDataList);

client.put(clientPolicy.writePolicyDefault, key, bin1, bin2);

Record record = client.get(null, key);
record = client.operate(client.writePolicyDefault, key,
ListOperation.setOrder(orderedBinName, ListOrder.ORDERED),
ListOperation.getByValueRange(orderedBinName, lowEnd0, highEnd0,
ListReturnType.VALUE),
ListOperation.getByValueRange(unorderedBinName, lowEnd0, highEnd0,
ListReturnType.VALUE),
ListOperation.getByValueRange(orderedBinName, lowEnd1, highEnd1,
ListReturnType.VALUE),
ListOperation.getByValueRange(unorderedBinName, lowEnd1, highEnd1,
ListReturnType.VALUE),
ListOperation.getByValueRange(orderedBinName, lowEnd2, highEnd2,
ListReturnType.VALUE),
ListOperation.getByValueRange(unorderedBinName, lowEnd2, highEnd2,
ListReturnType.VALUE)
);

List<?> resultOrdered = record.getList(orderedBinName);
List<?> resultUnordered = record.getList(unorderedBinName);

System.out.println("Mixed Type Data List: " + mixedDataList);
System.out.println("Created record with bins: " + orderedBinName + " and "
+ unorderedBinName);
System.out.println("The Unordered List range between " + lowEnd0 + " and " + highEnd0
+ " is " + resultUnordered.get(0));
System.out.println("The Ordered List range between " + lowEnd0 + " and " + highEnd0
+ " is " + resultOrdered.get(0));
System.out.println("The Unordered List range between " + lowEnd1 + " and " + highEnd1
+ " is " + resultUnordered.get(1));
System.out.println("The Ordered List range between " + lowEnd1 + " and " + highEnd1
+ " is " + resultOrdered.get(1));
System.out.println("The Unordered List range between " + lowEnd2 + " and " + highEnd2
+ " is " + resultUnordered.get(2));
System.out.println("The Ordered List range between " + lowEnd2 + " and " + highEnd2
+ " is " + resultOrdered.get(2));
System.out.println();


// Apply Rank Operations on Nested Lists of Varying Length.
// 1. Create Two Empty Lists.
// 2. Set the Sort Order for the Ordered List.
// 3. Put Lists of Varying Lengths in Both.

ArrayList<Integer> thisTuple0 = new ArrayList<Integer>();
thisTuple0.add(1);
thisTuple0.add(1);

ArrayList<Integer> thisTuple1 = new ArrayList<Integer>();
thisTuple1.add(1);
thisTuple1.add(3);

ArrayList<Integer> thisTuple2 = new ArrayList<Integer>();
thisTuple2.add(1);
thisTuple2.add(2);
thisTuple2.add(0);
thisTuple2.add(1);

ArrayList<Integer> thisTuple3 = new ArrayList<Integer>();
thisTuple3.add(1);
thisTuple3.add(2);


Integer listOfListsKey = 2;

Key key = new Key(listModelNamespace, listModelSet, listOfListsKey);
Bin bin1 = new Bin(orderedBinName, emptyList);
Bin bin2 = new Bin(unorderedBinName, emptyList);

client.put(clientPolicy.writePolicyDefault, key, bin1, bin2);

Record record = client.get(null, key);
record = client.operate(client.writePolicyDefault, key,
ListOperation.setOrder(orderedBinName, ListOrder.ORDERED),
ListOperation.append(orderedBinName, Value.get(thisTuple0)),
ListOperation.append(unorderedBinName, Value.get(thisTuple0)),
ListOperation.append(orderedBinName, Value.get(thisTuple1)),
ListOperation.append(unorderedBinName, Value.get(thisTuple1)),
ListOperation.append(orderedBinName, Value.get(thisTuple2)),
ListOperation.append(unorderedBinName, Value.get(thisTuple2)),
ListOperation.append(orderedBinName, Value.get(thisTuple3)),
ListOperation.append(unorderedBinName, Value.get(thisTuple3))
);
Record listWithTuples = client.get(null, key);

System.out.println("Created record with bins: " + orderedBinName + " and "
+ unorderedBinName);
System.out.println("Configured ordering policy to bin: " + orderedBinName);
System.out.println("The Unordered List is " + listWithTuples.getValue(unorderedBinName));
System.out.println("The Ordered List is " + listWithTuples.getValue(orderedBinName));
System.out.println();


// Apply Interval Operations on Nested Lists.
// 1. Create a List of Tuples.
// 2. Put the List of Tuples in an Ordered and an Unordered Bin.
// 3. Find the Interval between [1, NIL] and [2, NIL].
// 4. Find the Interval between [1, NIL] and [1, INF].

ArrayList<Integer> subTuple0 = new ArrayList<Integer>();
subTuple0.add(2);
subTuple0.add(7);

ArrayList<Integer> subTuple1 = new ArrayList<Integer>();
subTuple1.add(3);
subTuple1.add(1);

ArrayList<Integer> subTuple2 = new ArrayList<Integer>();
subTuple2.add(1);
subTuple2.add(2);

ArrayList<Integer> subTuple3 = new ArrayList<Integer>();
subTuple3.add(2);
subTuple3.add(5);

ArrayList<Integer> subTuple4 = new ArrayList<Integer>();
subTuple4.add(1);
subTuple4.add(1);

ArrayList<Integer> subTuple5 = new ArrayList<Integer>();
subTuple5.add(0);
subTuple5.add(3);

ArrayList<Value> tupleList = new ArrayList<Value>();
tupleList.add(Value.get(subTuple0));
tupleList.add(Value.get(subTuple1));
tupleList.add(Value.get(subTuple2));
tupleList.add(Value.get(subTuple3));
tupleList.add(Value.get(subTuple4));
tupleList.add(Value.get(subTuple5));


ArrayList<Value> lowTuple0 = new ArrayList<Value>();
lowTuple0.add(Value.get(1));
lowTuple0.add(Value.NULL);

ArrayList<Value> highTuple0 = new ArrayList<Value>();
highTuple0.add(Value.get(2));
highTuple0.add(Value.NULL);

ArrayList<Value> lowTuple1 = new ArrayList<Value>();
lowTuple1.add(Value.get(1));
lowTuple1.add(Value.NULL);

ArrayList<Value> highTuple1 = new ArrayList<Value>();
highTuple1.add(Value.get(1));
highTuple1.add(Value.INFINITY);

Integer tupleKey = 3;

Key key = new Key(listModelNamespace, listModelSet, tupleKey);
Bin bin1 = new Bin(orderedBinName, tupleList);
Bin bin2 = new Bin(unorderedBinName, tupleList);

client.put(clientPolicy.writePolicyDefault, key, bin1, bin2);

Record tupleResults = client.operate(client.writePolicyDefault, key,
ListOperation.setOrder(orderedBinName, ListOrder.ORDERED),
ListOperation.getByValueRange(orderedBinName, Value.get(lowTuple0), Value.get(highTuple0),
ListReturnType.VALUE),
ListOperation.getByValueRange(unorderedBinName, Value.get(lowTuple0), Value.get(highTuple0),
ListReturnType.VALUE),
ListOperation.getByValueRange(orderedBinName, Value.get(lowTuple1), Value.get(highTuple1),
ListReturnType.VALUE),
ListOperation.getByValueRange(unorderedBinName, Value.get(lowTuple1), Value.get(highTuple1),
ListReturnType.VALUE)
);

List<?> orderedTuples = tupleResults.getList(orderedBinName);
List<?> unorderedTuples = tupleResults.getList(unorderedBinName);

System.out.println("Tuple List: " + tupleList);
System.out.println("Created record with bins: " + orderedBinName + " and "
+ unorderedBinName);
System.out.println("The Unordered List between " + lowTuple0 + " and " + highTuple0 + " is "
+ unorderedTuples.get(0));
System.out.println("The Ordered List between " + lowTuple0 + " and " + highTuple0 + " is "
+ orderedTuples.get(0));
System.out.println("The Unordered List between " + lowTuple1 + " and " + highTuple1 + " is "
+ unorderedTuples.get(1));
System.out.println("The Ordered List between " + lowTuple1 + " and " + highTuple1 + " is "
+ orderedTuples.get(1));
System.out.println();


// Example 1 – IoT Model.
// 1. Create Sample Data.
// 2. Find the Temperature between Minute 14063 and 14064.

ArrayList<Value> subTuple0 = new ArrayList<Value>();
subTuple0.add(Value.get(14062));
subTuple0.add(Value.get(39.04));

ArrayList<Value> subTuple1 = new ArrayList<Value>();
subTuple1.add(Value.get(14063));
subTuple1.add(Value.get(39.78));

ArrayList<Value> subTuple2 = new ArrayList<Value>();
subTuple2.add(Value.get(14065));
subTuple2.add(Value.get(40.07));

ArrayList<Value> subTuple3 = new ArrayList<Value>();
subTuple3.add(Value.get(14064));
subTuple3.add(Value.get(40.89));

ArrayList<Value> subTuple4 = new ArrayList<Value>();
subTuple4.add(Value.get(14066));
subTuple4.add(Value.get(41.18));

ArrayList<Value> subTuple5 = new ArrayList<Value>();
subTuple5.add(Value.get(14067));
subTuple5.add(Value.get(40.93));

ArrayList<Value> tupleListIoT = new ArrayList<Value>();
tupleListIoT.add(Value.get(subTuple0));
tupleListIoT.add(Value.get(subTuple1));
tupleListIoT.add(Value.get(subTuple2));
tupleListIoT.add(Value.get(subTuple3));
tupleListIoT.add(Value.get(subTuple4));
tupleListIoT.add(Value.get(subTuple5));

ArrayList<Value> lowTuple = new ArrayList<Value>();
lowTuple.add(Value.get(14063));
lowTuple.add(Value.NULL);

ArrayList<Value> highTuple = new ArrayList<Value>();
highTuple.add(Value.get(14064));
highTuple.add(Value.INFINITY);

Integer keyIoT = 4;

Key key = new Key(listModelNamespace, listModelSet, keyIoT);
Bin bin1 = new Bin(unorderedBinName, tupleListIoT);
ClientPolicy clientPolicy = new ClientPolicy();

client.put(clientPolicy.writePolicyDefault, key, bin1);
Record between14063and14064 = client.get(null, key);
between14063and14064 = client.operate(client.writePolicyDefault, key,
ListOperation.getByValueRange(unorderedBinName, Value.get(lowTuple), Value.get(highTuple),
ListReturnType.VALUE)
);

System.out.println("IoT Tuple List: " + tupleListIoT);
System.out.println("Created record with bin: " + unorderedBinName);
System.out.println("The readings between " + lowTuple + " and " + highTuple + " are "
+ between14063and14064.getValue(unorderedBinName));
System.out.println();


// Example 2 – 100 Meter Leaderboard Model.
// 1. Create Overlapping Datasets.
// 2. Put the First Dataset in a Sorted Aerospike Bin
// 3. Find the Closest World Record to 10.0 Seconds.
// 4. Insert the Overlapping Dataset.

ArrayList<Value> wr100One0 = new ArrayList<Value>();
wr100One0.add(Value.get(10.06));
wr100One0.add(Value.get("Bob Hayes"));
wr100One0.add(Value.get("Tokyo, Japan"));
wr100One0.add(Value.get("October 15, 1964"));

ArrayList<Value> wr100One1 = new ArrayList<Value>();
wr100One1.add(Value.get(10.03));
wr100One1.add(Value.get("Jim Hines"));
wr100One1.add(Value.get("Sacramento, USA"));
wr100One1.add(Value.get("June 20,1968"));

ArrayList<Value> wr100One2 = new ArrayList<Value>();
wr100One2.add(Value.get(10.02));
wr100One2.add(Value.get("Charles Greene"));
wr100One2.add(Value.get("Mexico City, Mexico"));
wr100One2.add(Value.get("October 13, 1968"));

ArrayList<Value> wr100One3 = new ArrayList<Value>();
wr100One3.add(Value.get(9.95));
wr100One3.add(Value.get("Jim Hines"));
wr100One3.add(Value.get("Mexico City, Mexico"));
wr100One3.add(Value.get("October 14, 1968"));

ArrayList<Value> wr100One4 = new ArrayList<Value>();
wr100One4.add(Value.get(9.93));
wr100One4.add(Value.get("Calvin Smith"));
wr100One4.add(Value.get("Colorado Springs, USA"));
wr100One4.add(Value.get("July 3, 1983"));

ArrayList<Value> wr100One5 = new ArrayList<Value>();
wr100One5.add(Value.get(9.93));
wr100One5.add(Value.get("Carl Lewis"));
wr100One5.add(Value.get("Rome, Italy"));
wr100One5.add(Value.get("August 30, 1987"));

ArrayList<Value> wr100One6 = new ArrayList<Value>();
wr100One6.add(Value.get(9.92));
wr100One6.add(Value.get("Carl Lewis"));
wr100One6.add(Value.get("Seoul, South Korea"));
wr100One6.add(Value.get("September 24, 1988"));


ArrayList<Value> wr100m1List = new ArrayList<Value>();
wr100m1List.add(Value.get(wr100One0));
wr100m1List.add(Value.get(wr100One1));
wr100m1List.add(Value.get(wr100One2));
wr100m1List.add(Value.get(wr100One3));
wr100m1List.add(Value.get(wr100One4));
wr100m1List.add(Value.get(wr100One5));
wr100m1List.add(Value.get(wr100One6));

ArrayList<Value> wr100Two0 = new ArrayList<Value>();
wr100Two0.add(Value.get(9.93));
wr100Two0.add(Value.get("Carl Lewis"));
wr100Two0.add(Value.get("Rome, Italy"));
wr100Two0.add(Value.get("August 30, 1987"));

ArrayList<Value> wr100Two1 = new ArrayList<Value>();
wr100Two1.add(Value.get(9.92));
wr100Two1.add(Value.get("Carl Lewis"));
wr100Two1.add(Value.get("Seoul, South Korea"));
wr100Two1.add(Value.get("September 24, 1988"));

ArrayList<Value> wr100Two2 = new ArrayList<Value>();
wr100Two2.add(Value.get(9.90));
wr100Two2.add(Value.get("Leroy Burrell"));
wr100Two2.add(Value.get("New York, USA"));
wr100Two2.add(Value.get("June 14, 1991"));

ArrayList<Value> wr100Two3 = new ArrayList<Value>();
wr100Two3.add(Value.get(9.86));
wr100Two3.add(Value.get("Carl Lewis"));
wr100Two3.add(Value.get("Tokyo, Japan"));
wr100Two3.add(Value.get("August 25, 1991"));

ArrayList<Value> wr100Two4 = new ArrayList<Value>();
wr100Two4.add(Value.get(9.85));
wr100Two4.add(Value.get("Leroy Burrell"));
wr100Two4.add(Value.get("Lausanne, Switzerland"));
wr100Two4.add(Value.get("July 6, 1994"));

ArrayList<Value> wr100Two5 = new ArrayList<Value>();
wr100Two5.add(Value.get(9.84));
wr100Two5.add(Value.get("Donovan Bailey"));
wr100Two5.add(Value.get("Atlanta, USA"));
wr100Two5.add(Value.get("July 27, 1996"));

ArrayList<Value> wr100Two6 = new ArrayList<Value>();
wr100Two6.add(Value.get(9.79));
wr100Two6.add(Value.get("Maurice Greene"));
wr100Two6.add(Value.get("Athens, Greece"));
wr100Two6.add(Value.get("June 16, 1999"));

ArrayList<Value> wr100Two7 = new ArrayList<Value>();
wr100Two7.add(Value.get(9.77));
wr100Two7.add(Value.get("Asafa Powell"));
wr100Two7.add(Value.get("Athens, Greece"));
wr100Two7.add(Value.get("June 14, 2005"));

ArrayList<Value> wr100Two8 = new ArrayList<Value>();
wr100Two8.add(Value.get(9.77));
wr100Two8.add(Value.get("Asafa Powell"));
wr100Two8.add(Value.get("Gateshead, England"));
wr100Two8.add(Value.get("June 11, 2006"));

ArrayList<Value> wr100Two9 = new ArrayList<Value>();
wr100Two9.add(Value.get(9.77));
wr100Two9.add(Value.get("Asafa Powell"));
wr100Two9.add(Value.get("Zurich, Switzerland"));
wr100Two9.add(Value.get("August 18, 2006"));

ArrayList<Value> wr100Two10 = new ArrayList<Value>();
wr100Two10.add(Value.get(9.74));
wr100Two10.add(Value.get("Asafa Powell"));
wr100Two10.add(Value.get("Rieti, Italy"));
wr100Two10.add(Value.get("September 9, 2007"));

ArrayList<Value> wr100Two11 = new ArrayList<Value>();
wr100Two11.add(Value.get(9.72));
wr100Two11.add(Value.get("Usain Bolt"));
wr100Two11.add(Value.get("New York, USA"));
wr100Two11.add(Value.get("May 31, 2008"));

ArrayList<Value> wr100Two12 = new ArrayList<Value>();
wr100Two12.add(Value.get(9.69));
wr100Two12.add(Value.get("Usain Bolt"));
wr100Two12.add(Value.get("Beijing, China"));
wr100Two12.add(Value.get("August 16, 2008"));

ArrayList<Value> wr100Two13 = new ArrayList<Value>();
wr100Two13.add(Value.get(9.58));
wr100Two13.add(Value.get("Usain Bolt"));
wr100Two13.add(Value.get("Berlin, Germany"));
wr100Two13.add(Value.get("August 16, 2009"));


ArrayList<Value> wr100m2List = new ArrayList<Value>();
wr100m2List.add(Value.get(wr100Two0));
wr100m2List.add(Value.get(wr100Two1));
wr100m2List.add(Value.get(wr100Two2));
wr100m2List.add(Value.get(wr100Two3));
wr100m2List.add(Value.get(wr100Two4));
wr100m2List.add(Value.get(wr100Two5));
wr100m2List.add(Value.get(wr100Two6));
wr100m2List.add(Value.get(wr100Two7));
wr100m2List.add(Value.get(wr100Two8));
wr100m2List.add(Value.get(wr100Two9));
wr100m2List.add(Value.get(wr100Two10));
wr100m2List.add(Value.get(wr100Two11));
wr100m2List.add(Value.get(wr100Two12));
wr100m2List.add(Value.get(wr100Two13));

ArrayList<Value> searchTuple = new ArrayList<Value>();
searchTuple.add(Value.get(10.0));
searchTuple.add(Value.NULL);

Integer searchRank = -1;
Integer searchQty = 2;


Integer keyWR = 5;
String listLeadersBinName = "leaders";
int listUniqueFlags = ListWriteFlags.ADD_UNIQUE
| ListWriteFlags.NO_FAIL
| ListWriteFlags.PARTIAL;

Key key = new Key(listModelNamespace, listModelSet, keyWR);
Bin bin1 = new Bin(listLeadersBinName, wr100m1List);
ListPolicy policyOrderedNoDupes = new ListPolicy(ListOrder.ORDERED, listUniqueFlags);

client.put(clientPolicy.writePolicyDefault, key, bin1);
Record closestTo10 = client.get(null, key);
closestTo10 = client.operate(client.writePolicyDefault, key,
ListOperation.setOrder(listLeadersBinName, ListOrder.ORDERED),
ListOperation.getByValueRelativeRankRange(listLeadersBinName, Value.get(searchTuple),
searchRank, searchQty, ListReturnType.VALUE),
ListOperation.appendItems(policyOrderedNoDupes, listLeadersBinName, wr100m2List)
);
Record fullLeadersList = client.get(null, key);

System.out.println("100m World Record Holder List 1: ");
System.out.println(wr100m1List);
System.out.println();
System.out.println("100m World Record Holder List 2: ");
System.out.println(wr100m2List);
System.out.println();
System.out.println("Created Record with Ordered Bin: " + listLeadersBinName);
System.out.println();
System.out.println("The Closest World Records to 10.0 seconds are " +
closestTo10.getList(listLeadersBinName).get(0));
System.out.println();
System.out.println("Created List Policy for Ordering and Adding Only Unique Items.");
System.out.println();
System.out.println("The complete, deduplicated Leaders List is: ");
System.out.println(fullLeadersList.getValue(listLeadersBinName));
System.out.println();


// Truncate the Set.

client.truncate(infoPolicy, listModelNamespace, listModelSet, null);
System.out.println("Set Truncated.");


// Close the Client Connections.

client.close();
System.out.println("Server connection closed.");

Output:

Initialized the client and connected to the cluster.

Put list into record with bins: ordered and unordered
Original Integer List: [1]
Appending the following list items to both lists: [4, 7, 3, 9, 26, 11]
The Unordered List is [1, 4, 7, 3, 9, 26, 11]
The Ordered List is [1, 3, 4, 7, 9, 11, 26]

Sub Mixed Type List: [25, y, 1]
Mixed Type Data List: [c, 3, 26, [25, y, 1], 11, 9, 4, a, 1, 7]
Created record with bins: ordered and unordered
The Unordered List range between null and 10 is [3, 9, 4, 1, 7]
The Ordered List range between null and 10 is [1, 3, 4, 7, 9]
The Unordered List range between a and [] is [c, a]
The Ordered List range between a and [] is [a, c]
The Unordered List range between [] and INF is [[25, y, 1]]
The Ordered List range between [] and INF is [[25, y, 1]]

Created record with bins: ordered and unordered
Configured ordering policy to bin: ordered
The Unordered List is [[1, 1], [1, 3], [1, 2, 0, 1], [1, 2]]
The Ordered List is [[1, 1], [1, 2], [1, 2, 0, 1], [1, 3]]

Tuple List: [[2, 7], [3, 1], [1, 2], [2, 5], [1, 1], [0, 3]]
Created record with bins: ordered and unordered
The Unordered List between [1, null] and [2, null] is [[1, 2], [1, 1]]
The Ordered List between [1, null] and [2, null] is [[1, 1], [1, 2]]
The Unordered List between [1, null] and [1, INF] is [[1, 2], [1, 1]]
The Ordered List between [1, null] and [1, INF] is [[1, 1], [1, 2]]

IoT Tuple List: [[14062, 39.04], [14063, 39.78], [14065, 40.07], [14064, 40.89], [14066, 41.18], [14067, 40.93]]
Created record with bin: unordered
The readings between [14063, null] and [14064, INF] are [[14063, 39.78], [14064, 40.89]]

100m World Record Holder List 1:
[[10.06, Bob Hayes, Tokyo, Japan, October 15, 1964], [10.03, Jim Hines, Sacramento, USA, June 20,1968], [10.02, Charles Greene, Mexico City, Mexico, October 13, 1968], [9.95, Jim Hines, Mexico City, Mexico, October 14, 1968], [9.93, Calvin Smith, Colorado Springs, USA, July 3, 1983], [9.93, Carl Lewis, Rome, Italy, August 30, 1987], [9.92, Carl Lewis, Seoul, South Korea, September 24, 1988]]

100m World Record Holder List 2:
[[9.93, Carl Lewis, Rome, Italy, August 30, 1987], [9.92, Carl Lewis, Seoul, South Korea, September 24, 1988], [9.9, Leroy Burrell, New York, USA, June 14, 1991], [9.86, Carl Lewis, Tokyo, Japan, August 25, 1991], [9.85, Leroy Burrell, Lausanne, Switzerland, July 6, 1994], [9.84, Donovan Bailey, Atlanta, USA, July 27, 1996], [9.79, Maurice Greene, Athens, Greece, June 16, 1999], [9.77, Asafa Powell, Athens, Greece, June 14, 2005], [9.77, Asafa Powell, Gateshead, England, June 11, 2006], [9.77, Asafa Powell, Zurich, Switzerland, August 18, 2006], [9.74, Asafa Powell, Rieti, Italy, September 9, 2007], [9.72, Usain Bolt, New York, USA, May 31, 2008], [9.69, Usain Bolt, Beijing, China, August 16, 2008], [9.58, Usain Bolt, Berlin, Germany, August 16, 2009]]

Created Record with Ordered Bin: leaders

The Closest World Records to 10.0 seconds are [[9.95, Jim Hines, Mexico City, Mexico, October 14, 1968], [10.02, Charles Greene, Mexico City, Mexico, October 13, 1968]]

Created List Policy for Ordering and Adding Only Unique Items.

The complete, deduplicated Leaders List is:
[[9.58, Usain Bolt, Berlin, Germany, August 16, 2009], [9.69, Usain Bolt, Beijing, China, August 16, 2008], [9.72, Usain Bolt, New York, USA, May 31, 2008], [9.74, Asafa Powell, Rieti, Italy, September 9, 2007], [9.77, Asafa Powell, Athens, Greece, June 14, 2005], [9.77, Asafa Powell, Gateshead, England, June 11, 2006], [9.77, Asafa Powell, Zurich, Switzerland, August 18, 2006], [9.79, Maurice Greene, Athens, Greece, June 16, 1999], [9.84, Donovan Bailey, Atlanta, USA, July 27, 1996], [9.85, Leroy Burrell, Lausanne, Switzerland, July 6, 1994], [9.86, Carl Lewis, Tokyo, Japan, August 25, 1991], [9.9, Leroy Burrell, New York, USA, June 14, 1991], [9.92, Carl Lewis, Seoul, South Korea, September 24, 1988], [9.93, Calvin Smith, Colorado Springs, USA, July 3, 1983], [9.93, Carl Lewis, Rome, Italy, August 30, 1987], [9.95, Jim Hines, Mexico City, Mexico, October 14, 1968], [10.02, Charles Greene, Mexico City, Mexico, October 13, 1968], [10.03, Jim Hines, Sacramento, USA, June 20,1968], [10.06, Bob Hayes, Tokyo, Japan, October 15, 1964]]

Set Truncated.
Server connection closed.

Takeaway – Sort for App Read/Write Performance

Since, the results are the same whether the data is ordered or unordered in the database. The question becomes, "Does sorting the data benefit application performance for reads/writes?"

What's Next?

Next Steps

Have questions? Don't hesitate to reach out if you have additional questions about working with lists at https://discuss.aerospike.com/.

Want to check out other Java notebooks?

  1. Hello, World
  2. Aerospike Query and UDF
  3. Simple Put Get Example
  4. Working with Twitter Data
  5. Working with Lists

Are you running this from Binder? Download the Aerospike Notebook Repo and work with Aerospike Database and Jupyter locally using a Docker container.

Additional Resources