This page describes an older version of the product. The latest stable version is 14.5.

Interacting with the Space

In this part of the tutorial we will demonstrate how to create a space and how you can interact with it. We will also demonstrate how you can improve your space search performance by using indexes and returning partial results.

Creating a Space

Let’s create a space called ‘xapTutorialSpace’ that is co-located within an application. This type of space is called embedded space.

When a client connects to a space, a proxy is created that holds a connection which implements the space API. All client interaction is performed through this proxy.

With XAP you can also create a Local Cache and a Local View.

Local Cache : This client side cache maintains any object used by the application. The cache data is loaded on demand (lazily), based on the client application’s read operations.

Local View : This client side cache maintains a specific subset of the data. The subset is predefined by the user. The cache is populated when the client application is started.
In both cases, updates are performed (objects are added/updated/removed) on the master space, the master space then propagates the changes to all relevant local views and caches.

The Space Object

XAP supports two types of objects that can interact with the Space, POJOs and Documents.

POJO

Any POJO can be used to interact with the space as long it follows the Java Beans convention. The POJO needs to implement a default constructor, setters and getters for every property you want to store in the Space.

The SpaceId

The space generates a unique identifier (UID) for every object in one of the following ways:

When a space object has no SpaceId attribute declared, the space auto-generates a UID for the object.

When a space object has an attribute which is declared as SpaceId and marked as auto-generate=false, the UID is generated based on the value of the ID attribute the user is setting.

When a space object has an attribute which is declared as SpaceId and marked as auto-generate=true, the UID is generated by the space and placed back into the attribute using the relevant setter method. In this case, the attribute must be of java.lang.String type.

Compound SpaceId

You might need to construct a space id that will be comprised from a user defined class rather than using a Numeric or String type field. In such a case your user defined class used as the SpaceId data type must implement the toString , hashCode and equals methods. The compound ID class must implement a toString method that return a unique String for each ID.
Learn more

Defining Routing

Partitioning is used when the total number of objects is too big to be stored in a single space. In this case we will divide the data into several partitions. By designating an attribute on the space class as a partitioning key, the space proxy will then know to which partition a particular instance of the space class belongs to. The space proxy uses the entry’s routing attribute hash code to determine the corresponding partition for it.

The routing attribute can be explicitly set using the @SpaceRouting annotation for POJO entries or via the SpaceTypeDescriptorBuilder for document entries. If the routing attribute is not explicitly set, the space id attribute is used for routing. If the space id attribute is not defined, the first indexed attribute (alphabetically) is used for routing, otherwise the first attribute (alphabetically) is used for routing.
Learn more

Space Document

The GigaSpaces document API exposes the space as Document Store. A document, which is represented by the class SpaceDocument, is essentially a collection of key-value pairs, where the keys are strings and the values are primitives, String, Date, other documents, or collections thereof. Unlike POJOs, which force users to design a fixed data schema (in the form of a class definition) and adhere to it, a document is much more dynamic, users can add and remove properties at runtime as necessary. A Document always belongs to a certain type, represented by the class SpaceTypeDescriptor.

To create a document we use a Map for its properties. The SpaceDocument object is instantiated by using the type name and properties. XAP provides a special implementation of a Hash Map called DocumentProperties that provides a fluent API.

Only properties with special roles like ID and Routing are part of the schema definition. These meta model settings cannot be changed without restarting the space or dropping the type, clearing all its instances and reintroducing it again.

It is possible to write a POJO to the space and read it back as a document, and vice versa. This scenario is useful when you want to read or modify POJO objects without loading the concrete java classes.
Learn more

Interacting with the Space

All space operations are relevant to both the POJO and Document.

Writing an object to space:

When writing an object to the space, the object is created in space if it does not exist. If it already exists in space it will be updated. This is the default behavior of the write operation.

There are several options to override the default behavior of the write operation. You can change the lifetime of an object by supplying a LEASE to the operation. You can also change the modifier on the operation to change the behavior.

In this example, we are writing an object to the space with zero delay, 10 seconds to live and write only if the object does not already exist in the space. If the object already exists, an exception will be thrown.
Learn more

Updating an object in space

When you want to update only a couple of attributes on an object in space, you can use the change operation and update specific fields or even nested fields or modify collections and maps without having to supply the entire collection or map for the operation. With the following change operation example it is not necessary to read the object first from the space to update it. The Change API reduces a normal two step operation to a one step operation. This operation can vastly improve performance when you have an object with many attributes and you only need to update one or a couple of attributes.

Query by Template

Template matching (match by example) is a simple way to query the space. The template is a POJO of the desired entry type, and the attributes which are set on the template (i.e. not null) are matched against the respective attributes of entries of the same type in the space. Attributes with null values are ignored (not matched).

The following examples assume the default constructor of the User class initializes all its attributes to null.

Template Matching support inheritance relationships, so that entries of a sub-class are visible in the context of the super class, but not the other way around.

SQL Query

The SQLQuery class is used to query the space with an SQL-like syntax. The query statement includes only the WHERE statement part. An SQLQuery is composed from the class of entry to query and an expression in SQL syntax.

Parameterized Queries

You can separate the values for the SQL criteria expression by placing a ‘?’ symbol instead of the actual value in the expression. When executing the query, the conditions that includes ‘?’ are replaced with the corresponding parameter values supplied via the setParameter method.

Nested property queries

Many times a class has embedded classes as attributes. You can query for attributes within the embedded classes. Matching a nested attribute is done by specifying a Path which describes how to obtain its value. For example, our user class has an embedded attribute of an Address that has a zipCode attribute.

Here is an example how you can query the space for all users that have a zip code of ‘12345’.

There are several additional query options available. For example you can query Nested Maps by key,query with Regular Expression, Enum attributes and others.
Learn more

Query returning partial results

In some cases when querying the space for objects only specific attributes of an objects are required and not the entire object (delta read). For that purpose the Projection API can be used where you can specify which attributes are of interest and the space will only populate these attributes with the actual data when the result is returned back to the user. This approach reduces network overhead and can vastly improve performance.

In this example below we are just interested in the name attribute of the user object:

Aggregation

The Aggregators allow you to perform the entire aggregation activity at the space side avoiding any data retrieval back to the client side. Only the result of each aggregation activity performed with each partition is returned back to the client side where all the results are reduced and returned to the client application.

import static org.openspaces.extensions.QueryExtension.*;
...
SQLQuery<Employee> query = new SQLQuery<Employee>(Employee.class,"country=? OR country=? ");
query.setParameter(1, "UK");
query.setParameter(2, "U.S.A");
// retrieve the maximum value stored in the field "age"
Number maxAgeInSpace = max(space, query, "age");
/// retrieve the minimum value stored in the field "age"
Number minAgeInSpace = min(space, query, "age");
// Sum the "age" field on all space objects.
Number combinedAgeInSpace = sum(space, query, "age");
// Sum's the "age" field on all space objects then divides by the number of space objects.
Double averageAge = average(space, query, "age");
// Retrieve the space object with the highest value for the field "age".
Person oldestPersonInSpace = maxEntry(space, query, "age");
/// Retrieve the space object with the lowest value for the field "age".
Person youngestPersonInSpace = minEntry(space, query, "age");

XAP also supports, Compound, Embedded Fields and Group Aggregation.
Learn more

Indexing

To improve performance, it is possible to index one or more attributes for an object. The space maintains additional data for indexed attributes, which shortens the time required to determine a match resulting in improved performance. However, indexes consume more resources and impacts the write operations performance.

Inheritance

By default, an attribute’s index is inherited in sub classes (i.e. if an attribute is indexed in a super class, it is also indexed in a sub class). If you need to change the index type of an attribute in a subclass you can override the attribute and annotate it with @SpaceIndex using the requested index type (to disable indexing use NONE).

There are several additional indexing options available. For example you can index nested attributes, Nested Maps, Collections, nested attributes within a Collection, free text search and others.
Learn more

Best Practice

When you code your space classes make sure:

there are indexes for all relevant attributes including nested attributes you use for queries

numeric attribute queried with between / greater / less than should have an extended index.

compound indexes should be used for attributes queried using AND query

space classes have empty no arg constructor

all nested classes are serializable

do not use int, long, etc. integer attributes, instead use Long.

when possible use writeMultiple.

use projection for read/readMultiple

use clear for data removal and not take or takeMultiple

no huge collections with many items

use change api instead of update , especially if collections are used.