<jupyter_start><jupyter_text>Introduction to Transactions with Aerospike*Last updated: June 22, 2021*This notebook explains the basics of executing multiple operations on one record as a transaction. Aerospike was architected to process a high volume of concurrent real time reads and writes for Internet scale applications. Aerospike provides scale out performance by adding additional nodes or racks without changing application code. Application code specifies the necessary process and data policy to execute one or billions of Aerospike read and write operations. This notebook covers:* Discrete operations:   * Record operations   * Operations on simple data types:      * Strings      * Integers      * Doubles   * Operations on complex data types:      * Blobs      * HyperLogLogs      * Lists      * Maps      * GeoJSON* Simple transactions combining all of the above. This notebook does not detail replication across a cluster. This [Jupyter Notebook](https://jupyter-notebook.readthedocs.io/en/stable/notebook.html) 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](https://github.com/markprincely/aerospike-dev-notebooks.docker).  Notebook Setup  Import Jupyter Java Integration<jupyter_code>import io.github.spencerpark.ijava.IJava;
import io.github.spencerpark.jupyter.kernel.magic.common.Shell;

IJava.getKernelInstance().getMagics().registerMagics(Shell.class);<jupyter_output><empty_output><jupyter_text>Start Aerospike<jupyter_code>%sh asd<jupyter_output><empty_output><jupyter_text>Download the Aerospike Java Client<jupyter_code>%%loadFromPOM
<dependencies>
  <dependency>
    <groupId>com.aerospike</groupId>
    <artifactId>aerospike-client</artifactId>
    <version>5.0.0</version>
  </dependency>
</dependencies><jupyter_output><empty_output><jupyter_text>Start the Aerospike Java Client and ConnectThe 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.<jupyter_code>import com.aerospike.client.AerospikeClient;

AerospikeClient client = new AerospikeClient("localhost", 3000);
System.out.println("Initialized the client and connected to the cluster.");<jupyter_output>Initialized the client and connected to the cluster.<jupyter_text>Aerospike Provides Intuitive Atomic Reads and WritesAerospike provides client APIs to read and write different types of data. Each record read or write operation that an Aerospike server or cluster executes as an atomic (ACID) operation.For additional information on Aerospike's single-record variant of ACID compliance, go [here](https://www.aerospike.com/docs/architecture/acid.html).  Operate Applies One or More OperationsFor the case where an application uses Aerospike as a key/value store without applying [Aerospike data types](https://www.aerospike.com/docs/guide/data-types.html) to data, the [AerospikeClient](https://www.aerospike.com/apidocs/java/com/aerospike/client/AerospikeClient.html) provides the super fast, basic getters and setters for bins of data. The most frequently used and simplest technique to execute more than one operation in an atomic fashion is the Operate API. Using this API, the Aerospike client can execute a single read or write operation or complex combinations of reads and writesFor more information on Operate, go [here](https://www.aerospike.com/apidocs/java/com/aerospike/client/Operation.html).For more information on applying multiple operations to a record, go [here](https://aerospike.com/docs/client/java/usage/kvs/multiops.html).  Using Discrete Operations on a Full RecordAerospike provides the following record operations:* Get – Read a record.* Getheader – Read a record's TTL and generation counter.* Touch – Increase a record's generation counter.* Delete – Delete a record.  Create Test DataCreate a simple instance of every Aerospike data type.<jupyter_code>import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.HashMap;

String txnString = "atomic";
Integer txnInteger = 8;
Double txnDouble = 6.022;
byte[] txnBlob = new byte[] {0b00000001, 0b00000010, 0b00000011, 0b00000100, 0b00000101};
String txnGeo = String.format("{ \"type\": \"Polygon\", \"coordinates\": [ [[-122.500, 37.000], [-121.000, 37.000], [-121.000, 38.080], [-122.500, 38.080], [-122.500, 37.000]] ] }");
ArrayList<Integer> txnList = new ArrayList<Integer>();
txnList.add(1);

HashMap<Integer, Integer> txnMap = new HashMap <Integer, Integer>();
txnMap.put(2, 4);

System.out.println("String: " + txnString);
System.out.println("Integer: " + txnInteger);
System.out.println("Double: " + txnDouble);
System.out.println("Blob: " + Arrays.toString(txnBlob));
System.out.println("HLL: Starts with no data.");
System.out.println("Geo: " + txnGeo);
System.out.println("List: " + txnList);
System.out.println("Map: " + txnMap);<jupyter_output>String: atomic
Integer: 8
Double: 6.022
Blob: [1, 2, 3, 4, 5]
HLL: Starts with no data.
Geo: { "type": "Polygon", "coordinates": [ [[-122.500, 37.000], [-121.000, 37.000], [-121.000, 38.080], [-122.500, 38.080], [-122.500, 37.000]] ] }
List: [1]
Map: {2=4}<jupyter_text>Put Data Into An Aerospike Record<jupyter_code>import com.aerospike.client.Key;
import com.aerospike.client.Bin;
import com.aerospike.client.Value;
import com.aerospike.client.policy.ClientPolicy;

Integer theKey = 0;
String txnSet = "txnset";
String txnNamespace = "test";

String txnStringBin = "str";
String txnIntegerBin = "int";
String txnDoubleBin = "double";
String txnBlobBin = "blob";
String txnHLLBin = "hll";
String txnGeoBin = "geo";
String txnListBin = "list";
String txnMapBin = "map";
ClientPolicy clientPolicy = new ClientPolicy();

Key key = new Key(txnNamespace, txnSet, theKey);
Bin bin0 = new Bin(txnStringBin, txnString);
Bin bin1 = new Bin(txnIntegerBin, txnInteger);
Bin bin2 = new Bin(txnDoubleBin, txnDouble);
Bin bin3 = new Bin(txnBlobBin, txnBlob);
Bin bin4 = new Bin(txnHLLBin, Value.getAsNull());
Bin bin5 = new Bin(txnGeoBin, Value.getAsGeoJSON(txnGeo));
Bin bin6 = new Bin(txnListBin, txnList);
Bin bin7 = new Bin(txnMapBin, txnMap);

client.put(clientPolicy.writePolicyDefault, key, bin0, bin1, bin2, bin3, bin5, bin6, bin7);

System.out.println("Put data into Aerospike: "
                    + txnStringBin + ", "
                    + txnIntegerBin + ", " 
                    + txnDoubleBin + ", " 
                    + txnBlobBin + ", " 
                    + txnHLLBin + ", " 
                    + txnGeoBin + ", " 
                    + txnListBin + ", " 
                    + txnMapBin);<jupyter_output>Put data into Aerospike: str, int, double, blob, hll, geo, list, map<jupyter_text>Get the Record<jupyter_code>import com.aerospike.client.Record;

Key key = new Key(txnNamespace, txnSet, theKey);
Record record = client.get(null, key);
System.out.println(record);<jupyter_output>(gen:4),(exp:358043147),(bins:(str:atomic),(int:8),(double:6.022),(blob:[B@5c70658),(geo:{ "type": "Polygon", "coordinates": [ [[-122.500, 37.000], [-121.000, 37.000], [-121.000, 38.080], [-122.500, 38.080], [-122.500, 37.000]] ] }),(list:[1]),(map:{2=4}),(hll:00080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000400000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000c0000000000))<jupyter_text>Get the Record Header<jupyter_code>Key key = new Key(txnNamespace, txnSet, theKey);
Record record = client.getHeader(null, key);
System.out.println(record);<jupyter_output>(gen:4),(exp:358043147),(bins:null)<jupyter_text>Touch the Record<jupyter_code>Key key = new Key(txnNamespace, txnSet, theKey);
client.touch(client.writePolicyDefault, key);
Record record = client.get(client.writePolicyDefault, key);
System.out.println(record);<jupyter_output>(gen:5),(exp:358043147),(bins:(str:atomic),(int:8),(double:6.022),(blob:[B@3efad74b),(geo:{ "type": "Polygon", "coordinates": [ [[-122.500, 37.000], [-121.000, 37.000], [-121.000, 38.080], [-122.500, 38.080], [-122.500, 37.000]] ] }),(list:[1]),(map:{2=4}),(hll:00080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000400000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000c0000000000))<jupyter_text>Operating on Simple Bin DataWhen operating on simple data–Strings, Integers, and Doubles–, Aerospike provides standard create, read, update, and delete operations and also increment operations, like prepend/append  and add. For more information on record operations and simple data operations, go [here](https://www.aerospike.com/apidocs/java/com/aerospike/client/Operation.html).    Operating on String DataAppend to a string.<jupyter_code>String txnAppendString = "-operation";
bin0 = new Bin(txnStringBin, txnAppendString);

Key key = new Key(txnNamespace, txnSet, theKey);
Record record = client.get(client.writePolicyDefault, key);
client.append(client.writePolicyDefault, key, bin0);
Record after = client.get(client.writePolicyDefault, key);

System.out.println("Before, the " + txnStringBin + " was - " + record.getValue(txnStringBin));
System.out.println("  After, the " + txnStringBin + " is - " + after.getValue(txnStringBin));<jupyter_output>Before, the str was - atomic
  After, the str is - atomic-operation<jupyter_text>Operating on Integer DataAdd to an integer.<jupyter_code>Integer txnAddInt = 5;
Bin binIntAdd = new Bin(txnIntegerBin, txnAddInt);

Key key = new Key(txnNamespace, txnSet, theKey);
Record record = client.get(client.writePolicyDefault, key);
client.add(client.writePolicyDefault, key, binIntAdd);
Record after = client.get(client.writePolicyDefault, key);

System.out.println("Before, the " + txnIntegerBin + " was - " + record.getValue(txnIntegerBin));
System.out.println("  After, the " + txnIntegerBin + " is - " + after.getValue(txnIntegerBin));<jupyter_output>Before, the int was - 8
  After, the int is - 13<jupyter_text>Operating on Double DataSubtract from a double.<jupyter_code>Double txnAddDouble = -3.142;
Bin binDoubleAdd = new Bin(txnDoubleBin, txnAddDouble);

Key key = new Key(txnNamespace, txnSet, theKey);
Record record = client.get(client.writePolicyDefault, key);
client.add(client.writePolicyDefault, key, binDoubleAdd);
Record after = client.get(client.writePolicyDefault, key);

System.out.println("Before, the " + txnDoubleBin + " was - " + record.getValue(txnDoubleBin));
System.out.println("  After, the " + txnDoubleBin + " is - " + after.getValue(txnDoubleBin));<jupyter_output>Before, the double was - 6.022
  After, the double is - 2.8800000000000003<jupyter_text>Operating on Complex Data TypesAerospike also provides data-type-specific operations to work with complex data types:* Collection Data Types   * Lists   * Maps* Blob/Bit Data* HyperLogLog (as a HyperMinHash)* GeoJSON  Operating on ListsAppend 5 to the list.Aerospike provides operations to create and manage:* a simple list* list containing lists* list containing mapsFor a tutorial on working with lists, go [here](java-working_with_lists.ipynb). For more information on ListOperations, go [here](https://www.aerospike.com/apidocs/java/com/aerospike/client/cdt/ListOperation.html).<jupyter_code>import com.aerospike.client.cdt.ListOperation;

Integer listAddition = 5;

Key key = new Key(txnNamespace, txnSet, theKey);
Record record = client.get(client.writePolicyDefault, key);
client.operate(client.writePolicyDefault, key, 
    ListOperation.append(txnListBin, Value.get(listAddition))
);
Record after = client.get(client.writePolicyDefault, key);

System.out.println("Before, the " + txnListBin + " was - " + record.getValue(txnListBin));
System.out.println("  After, the " + txnListBin + " is - " + after.getValue(txnListBin));<jupyter_output>Before, the list was - [1]
  After, the list is - [1, 5]<jupyter_text>Operating on MapsIncrement the Value of mapkey 2 by 57. Aerospike provides operations to create and manage:* a map* a map containing lists* a map containing mapsFor a tutorial on working with maps, go [here]((java-working_with_maps.ipynb)).For more information on Map Operations, go [here](https://www.aerospike.com/apidocs/java/com/aerospike/client/cdt/MapOperation.html).<jupyter_code>import com.aerospike.client.cdt.MapOperation;
import com.aerospike.client.cdt.MapPolicy;

Integer mapKey = 2;
Integer mapIncrementValue = 57;

MapPolicy txnMapPolicy = new MapPolicy();
Key key = new Key(txnNamespace, txnSet, theKey);
Record record = client.get(client.writePolicyDefault, key);
client.operate(client.writePolicyDefault, key, 
    MapOperation.increment(txnMapPolicy, txnMapBin, Value.get(mapKey), Value.get(mapIncrementValue))
);
Record after = client.get(client.writePolicyDefault, key);

System.out.println("Before, the " + txnMapBin + " was - " + record.getValue(txnMapBin));
System.out.println("  After, the " + txnMapBin + " is - " + after.getValue(txnMapBin));<jupyter_output>Before, the map was - {2=4}
  After, the map is - {2=61}<jupyter_text>Operating on Blob/Bit DataIn addition to CRUD operations, Aerospike provides standard bit wise operations, such as logical operators (AND, OR, NOT, etc.), add/subtract, and shifts.For more information on Bit Operations, go [here](https://www.aerospike.com/apidocs/java/com/aerospike/client/operation/BitOperation.html).<jupyter_code>import com.aerospike.client.operation.BitOperation;
import com.aerospike.client.operation.BitPolicy;

byte[] bitsToSet = new byte[] {(byte)0b11100000};
Integer bitSize = 8;
Integer bitOffset = 13;

BitPolicy bitPolicy = new BitPolicy();
Key key = new Key(txnNamespace, txnSet, theKey);
Record record = client.get(client.writePolicyDefault, key);
client.operate(client.writePolicyDefault, key,
     BitOperation.set(bitPolicy.Default, txnBlobBin, bitOffset, bitSize, bitsToSet)
);
Record after = client.get(client.writePolicyDefault, key);

byte[] beforeBytes = (byte[])record.getValue(txnBlobBin);
byte[] afterBytes = (byte[])after.getValue(txnBlobBin);

System.out.println("Before, the " + txnBlobBin + " was - " + Arrays.toString(beforeBytes));
System.out.println("  After, the " + txnBlobBin + " is - " + Arrays.toString(afterBytes));<jupyter_output>Before, the blob was - [1, 2, 3, 4, 5]
  After, the blob is - [1, 7, 3, 4, 5]<jupyter_text>Operating on HyperLogLog DataInit the HyperLogLog bin.HyperLogLog is a probabilistic data type used for counting really large data sets. Aerospike provides operations to:* Maintain the data type (init, reset, etc.)* Add data to these data sets.* Compare HyperLogLog data (intersection, unions, etc.).For more information on HyperLogLog Operations, go [here](https://www.aerospike.com/apidocs/java/com/aerospike/client/operation/HLLOperation.html).<jupyter_code>import com.aerospike.client.operation.HLLOperation;
import com.aerospike.client.operation.HLLPolicy;

HLLPolicy defHLLPolicy = new HLLPolicy();
Integer bitsHLLIndex = 8;

Key key = new Key(txnNamespace, txnSet, theKey);
Record record = client.get(client.writePolicyDefault, key);
client.operate(client.writePolicyDefault, key, 
    HLLOperation.init(defHLLPolicy, txnHLLBin, bitsHLLIndex)
);
Record after = client.get(client.writePolicyDefault, key);

System.out.println("Before, the " + txnHLLBin + " was - " + record.getValue(txnHLLBin));
System.out.println("  After, the " + txnHLLBin + " is - " + after.getValue(txnHLLBin));<jupyter_output>Before, the hll was - 00080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000400000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000c0000000000
  After, the hll is - 0008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000<jupyter_text>Operating on GeoJSONGet GeoJSON data.For the purposes of simple transactions, Aerospike quickly stores and retrieves GeoJSON data in bins, and optionally nested in maps. In addition, Aerospike validates GeoJSON and processes Geospatial queries, including circle queries. For more information on using Aerospike for geospatial indexes and queries, go [here](https://www.aerospike.com/docs/guide/geospatial.html).<jupyter_code>Key key = new Key(txnNamespace, txnSet, theKey);
Record pullGeo = client.get(client.writePolicyDefault, key, txnGeoBin);

System.out.println("The " + txnGeoBin + " is - " + pullGeo.getValue(txnGeoBin));<jupyter_output>The geo is - { "type": "Polygon", "coordinates": [ [[-122.500, 37.000], [-121.000, 37.000], [-121.000, 38.080], [-122.500, 38.080], [-122.500, 37.000]] ] }<jupyter_text>Performing a Simple Transaction on a RecordThe above operations were each performed as atomic operations. **Operate** executes multiple operations to one or more bins during a single record lock in an ACID-compliant fashion. Results are returned in an array for each bin.    Execute All of the Previous Operations as a Transaction1. Create data for each data type.2. Put it into Aerospike.3. Apply the following operations as one transaction.   1. Touch the record.   2. Append to the string.   3. Increment the integer.   4. Subtract from the double.   5. Put an item in the list.   6. Put a new value in the map.   7. Set bits in the blob.   8. Init and add set elements to the hyperloglog.   9. Get the GeoJSON.<jupyter_code>// Create data for each data type.

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

String txnString = "atomic";
Integer txnInteger = 8;
Double txnDouble = 6.022;
byte[] txnBlob = new byte[] {0b00000001, 0b00000010, 0b00000011, 0b00000100, 0b00000101};
String txnGeo = String.format("{ \"type\": \"Polygon\", \"coordinates\": [ [[-122.500, 37.000], [-121.000, 37.000], [-121.000, 38.080], [-122.500, 38.080], [-122.500, 37.000]] ] }");
ArrayList<Integer> txnList = new ArrayList<Integer>();
txnList.add(1);

HashMap<Integer, Integer> txnMap = new HashMap <Integer, Integer>();
txnMap.put(2, 4);

System.out.println("--Initial Data–-");
System.out.println("String: " + txnString);
System.out.println("Integer: " + txnInteger);
System.out.println("Double: " + txnDouble);
System.out.println("Blob: " + Arrays.toString(txnBlob));
System.out.println("HLL: Starts with no data.");
System.out.println("Geo: " + txnGeo);
System.out.println("List: " + txnList);
System.out.println("Map: " + txnMap);
System.out.println();

// Put it into Aerospike.

import com.aerospike.client.AerospikeClient;
import com.aerospike.client.Key;
import com.aerospike.client.Bin;
import com.aerospike.client.Value;
import com.aerospike.client.policy.ClientPolicy;
import com.aerospike.client.Operation;
import com.aerospike.client.cdt.ListOperation;
import com.aerospike.client.cdt.MapOperation;
import com.aerospike.client.cdt.MapPolicy;
import com.aerospike.client.operation.BitOperation;
import com.aerospike.client.operation.BitPolicy;
import com.aerospike.client.operation.HLLOperation;
import com.aerospike.client.operation.HLLPolicy;


Integer theKey = 0;
String txnSet = "txnset";
String txnNamespace = "test";

String txnStringBin = "str";
String txnIntegerBin = "int";
String txnDoubleBin = "double";
String txnBlobBin = "blob";
String txnHLLBin = "hll";
String txnGeoBin = "geo";
String txnListBin = "list";
String txnMapBin = "map";

AerospikeClient client = new AerospikeClient("localhost", 3000);

ClientPolicy clientPolicy = new ClientPolicy();
BitPolicy bitPolicy = new BitPolicy();
HLLPolicy defHLLPolicy = new HLLPolicy();
MapPolicy txnMapPolicy = new MapPolicy();

Key key = new Key(txnNamespace, txnSet, theKey);

Bin bin0 = new Bin(txnStringBin, txnString);
Bin bin1 = new Bin(txnIntegerBin, txnInteger);
Bin bin2 = new Bin(txnDoubleBin, txnDouble);
Bin bin3 = new Bin(txnBlobBin, txnBlob);
Bin bin4 = new Bin(txnHLLBin, Value.getAsNull());
Bin bin5 = new Bin(txnGeoBin, Value.getAsGeoJSON(txnGeo));
Bin bin6 = new Bin(txnListBin, txnList);
Bin bin7 = new Bin(txnMapBin, txnMap);

client.put(clientPolicy.writePolicyDefault, key, bin0, bin1, bin2, bin3, bin5, bin6, bin7);


// Apply the following operations as one transaction.
// 1. Touch the record.
// 2. Append to the string.
// 3. Increment the integer.
// 4. Subtract from the double.
// 5. Put an item in the list.
// 6. Increment a value in the map.
// 7. Set bits in the blob.
// 8. Init and add set elements to the hyperloglog.
// 9. Get the GeoJSON.

String txnAppendString = "-transactions";
Bin binStrAppend = new Bin(txnStringBin, txnAppendString);
Integer txnAddInt = 5;
Bin binIntAdd = new Bin(txnIntegerBin, txnAddInt);
Double txnAddDouble = -3.142;
Bin binDoubleSub = new Bin(txnDoubleBin, txnAddDouble);
byte[] bitsToSet = new byte[] {(byte)0b11100000};
Integer bitSize = 8;
Integer bitOffset = 13;
Integer bitsHLLIndex = 8;
Integer listAddition = 5;
Integer mapKey = 2;
Integer mapIncrementValue = 57;
ArrayList<Value> dataListForHLL = new ArrayList<Value>();
dataListForHLL.add(Value.get(txnAddInt));
dataListForHLL.add(Value.get(bitSize));
dataListForHLL.add(Value.get(bitOffset));
dataListForHLL.add(Value.get(bitsHLLIndex));
dataListForHLL.add(Value.get(listAddition));
dataListForHLL.add(Value.get(mapKey));
dataListForHLL.add(Value.get(mapIncrementValue));

Record beforeOps = client.get(client.writePolicyDefault, key);
Record operationsRecord = client.operate(client.writePolicyDefault, key,
        Operation.touch(),
        Operation.append(binStrAppend),
        Operation.add(binIntAdd),
        Operation.add(binDoubleSub),
        ListOperation.append(txnListBin, Value.get(listAddition)),
        MapOperation.increment(txnMapPolicy, txnMapBin, Value.get(mapKey), Value.get(mapIncrementValue)),
        BitOperation.set(bitPolicy.Default, txnBlobBin, bitOffset, bitSize, bitsToSet),
        HLLOperation.init(defHLLPolicy, txnHLLBin, bitsHLLIndex),
        HLLOperation.add(defHLLPolicy, txnHLLBin, dataListForHLL, bitsHLLIndex)
    );
Record afterOps = client.get(client.writePolicyDefault, key);

System.out.println("--The Data in Aerospike–-");
System.out.println(beforeOps);
System.out.println();
System.out.println("--Operation Details–-");
System.out.println("Before, the " + txnStringBin + " was - " + beforeOps.getValue(txnStringBin));
System.out.println("  After, the " + txnStringBin + " is - " + afterOps.getValue(txnStringBin));
System.out.println();
System.out.println("Before, the " + txnIntegerBin + " was - " + beforeOps.getValue(txnIntegerBin));
System.out.println("  After, the " + txnIntegerBin + " is - " + afterOps.getValue(txnIntegerBin));
System.out.println();
System.out.println("Before, the " + txnDoubleBin + " was - " + beforeOps.getValue(txnDoubleBin));
System.out.println("  After, the " + txnDoubleBin + " is - " + afterOps.getValue(txnDoubleBin));
System.out.println();
System.out.println("Before, the " + txnListBin + " was - " + beforeOps.getValue(txnListBin));
System.out.println("  After, the " + txnListBin + " is - " + afterOps.getValue(txnListBin));
System.out.println();
System.out.println("Before, the " + txnMapBin + " was - " + beforeOps.getValue(txnMapBin));
System.out.println("  After, the " + txnMapBin + " is - " + afterOps.getValue(txnMapBin));
System.out.println();
byte[] beforeBytes = (byte[])beforeOps.getValue(txnBlobBin);
byte[] afterBytes = (byte[])afterOps.getValue(txnBlobBin);
System.out.println("Before, the " + txnBlobBin + " was - " + Arrays.toString(beforeBytes));
System.out.println("  After, the " + txnBlobBin + " is - " + Arrays.toString(afterBytes));
System.out.println();
System.out.println("Before, the " + txnHLLBin + " was - " + beforeOps.getValue(txnHLLBin));
System.out.println("  After, the " + txnHLLBin + " is - " + afterOps.getValue(txnHLLBin));
System.out.println();
System.out.println("The " + txnGeoBin + " is - " + afterOps.getValue(txnGeoBin));
System.out.println();

System.out.println("--The Record After the Operations–-");
System.out.println(afterOps);<jupyter_output>--Initial Data–-
String: atomic
Integer: 8
Double: 6.022
Blob: [1, 2, 3, 4, 5]
HLL: Starts with no data.
Geo: { "type": "Polygon", "coordinates": [ [[-122.500, 37.000], [-121.000, 37.000], [-121.000, 38.080], [-122.500, 38.080], [-122.500, 37.000]] ] }
List: [1]
Map: {2=4}

--The Data in Aerospike–-
(gen:13),(exp:358043150),(bins:(str:atomic),(int:8),(double:6.022),(blob:[B@42a7022c),(geo:{ "type": "Polygon", "coordinates": [ [[-122.500, 37.000], [-121.000, 37.000], [-121.000, 38.080], [-122.500, 38.080], [-122.500, 37.000]] ] }),(list:[1]),(map:{2=4}),(hll:0008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000))

--Operation Details–-
Befo[...]<jupyter_text>Use Write Policies To Replace Existence ChecksSimple transactions require arbitrary logic. The main technique to add conditional logic to these transactions is to apply a **write policy**.Write operations use *policy* with the policy flags to indicate how to behave when data does or does not exist. For example, if executing a simple transaction containing multiple operations including one map operation that uses the conditional logic `if (bin doesn't have a value), then put a default value into the bin`, apply that one operation using a write policy using the flags: * CREATE_ONLY – Only apply the write if the data doesn't exist.* NO_FAIL – Do not throw an error upon failure.* PARTIAL – Allow other operations to succeed.The default write policy if data exists in a bin is to merge data, whenever possible.Each complex data type has its own write mode policy options. * For information on Bit Write Flags, go [here](https://www.aerospike.com/apidocs/java/com/aerospike/client/operation/BitWriteFlags.html).* For information on HyperLogLog Write Flags, go [here](https://www.aerospike.com/apidocs/java/com/aerospike/client/operation/HLLWriteFlags.html). * For information on List Write Flags, go [here](https://www.aerospike.com/apidocs/java/com/aerospike/client/cdt/ListWriteFlags.html).* For information on Map Write Flags, go [here](https://www.aerospike.com/apidocs/java/com/aerospike/client/cdt/MapWriteFlags.html).Now, insert a new Mapkey:Value pair only if the mapkey doesn't already exist.<jupyter_code>import com.aerospike.client.cdt.MapOrder;
import com.aerospike.client.cdt.MapWriteFlags;

Integer txnDefaultMapkey=2;
Integer txnDefaultValue=1;

MapPolicy txnMapPolicy = new MapPolicy(MapOrder.UNORDERED, MapWriteFlags.CREATE_ONLY | MapWriteFlags.NO_FAIL | MapWriteFlags.PARTIAL);

Key key = new Key(txnNamespace, txnSet, theKey);
Record mapFailRecord = client.operate(client.writePolicyDefault, key,
        MapOperation.put(txnMapPolicy, txnMapBin, Value.get(txnDefaultMapkey), Value.get(txnDefaultValue))
    );
Record afterOps = client.get(client.writePolicyDefault, key);

System.out.println("The " + txnMapBin + " is - " + afterOps.getValue(txnMapBin));
System.out.println();<jupyter_output>The map is - {2=61}<jupyter_text>Use RMF or Record UDFs to Apply Other Conditional LogicIf a process does requires conditional logic to check data values before writing, the common practice is to use a Read-Modify-Write pattern to check the data and write only if the generation counter is the same as when read.For more information about Read-Modify-Write, go [here].(https://www.aerospike.com/blog/developers-understanding-aerospike-transactions/)  Notebook Cleanup  Truncate the SetTruncate the set from the Aerospike Database.<jupyter_code>import com.aerospike.client.policy.InfoPolicy;
InfoPolicy infoPolicy = new InfoPolicy();

client.truncate(infoPolicy, txnNamespace, txnSet, null);
System.out.println("Set Truncated.");<jupyter_output>Set Truncated.<jupyter_text>Close the Connection to Aerospike<jupyter_code>client.close();
System.out.println("Server connection closed.");<jupyter_output>Server connection closed.
{'fraction_non_alphanumeric': 0.11977525010278196, 'fraction_numerical': 0.09777990955187063, 'mean_word_length': 5.734886940470697, 'pattern_counts': {'":': 16, '<': 87, '<?xml version=': 0, '>': 87, 'https://': 18, 'lorem ipsum': 0, 'www.': 15, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 23, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '21', 'dir': 'jupyter-structured-clean-dedup', 'id': '145191', 'license': 'MIT', 'n_tokens_mistral': 11521, 'n_tokens_neox': 8769, 'n_words': 2375, 'path': 'notebooks/java/java-intro_to_transactions.ipynb', 'repo_name': 'markprincely/interactive-notebooks', 'size': '29188'}