Searching with Data Types

Although Riak Data Types function differently from other
Riak objects in some respects, when you’re using Search you can think of
them as normal Riak objects with special metadata attached (metadata
that you don’t need to worry about as a user). Riak’s counters, sets, and maps
can be indexed and have their contents searched just like other Riak
objects.

Data Type MIME Types

Like all objects stored in Riak, Riak Data Types are assigned content
types. Unlike other Riak objects, this happens automatically. When you
store, say, a counter in Riak, it will automatically be assigned the
type application/riak_counter. The table below provides the full list
of content types:

Data Type

Content Type

Counters

application/riak_counter

Sets

application/riak_set

Maps

application/riak_map

When using Search, you won’t need to worry about this, as Riak Data
Types are automatically indexed on the basis of these content types.

Data Type Schemas

There are two types of schemas related to Riak Data Types:

Top-level schemas relate to Data Types that are stored at the key
level (counters and sets)

As you can see from the default Search
schema,
each of the Data Types has its own default schema, with the exception of
maps, which means that the _yz_default schema will automatically index
Data Types on the basis of their assigned content type. This means that
there is no extra work involved in indexing Riak Data Types. You can
simply store them and begin querying, provided that they are properly
indexed, which is covered in the examples section below.

As mentioned above, there are no default schemas available for maps.
This is because maps are essentially carriers for the other Data Types.
Even when maps are embedded within other maps, all of the data that you
might wish to index and search is contained in counters, sets,
registers, and flags.

The sections immediately below provide the default schemas for each Riak
Data Type. Because you will not need to manipulate these default schemas
to search Data Types, they are provided only for reference.

To query embedded fields, you must provide the name of the field. The
table below provides some examples:

Query

Syntax

Maps containing a set called hobbies

hobbies_set:*

Maps containing a score counter over 50

score_counter:[50 TO *]

Maps containing disabled advanced flags

advanced_flag:false

Maps containing enabled advanced flags and score counters under 10

advanced_flag:true AND score_counter:[* TO 10]

You can also query maps within maps, which is covered in the Querying
maps within maps section below.

Data Types and Search Examples

In this section, we’ll start with two simple examples, one involving
counters and the other involving sets. Later on, we’ll introduce a
slightly more complex map example.

Counters Example

Let’s say that we’re storing scores in a multiplayer online game in
Riak. The game is called Boulderdash and it involves smashing digital
boulders armed with nothing but witty retorts and arcane trivia
knowledge. We’ll create and activate a bucket type for storing counters simply called
counters, like so:

At this point, all of the counters that we stored in any bucket with the
bucket type counters will be indexed in our scores index. So let’s
start playing with some counters. All counters will be stored in the
bucket people, while the key for each counter will be the username of
each player:

Now, all of the sets that we store in any bucket with the bucket type
sets will be automatically indexed as a set. So let’s say that we
store three sets for two different people describing their respective
hobbies, in the bucket people:

Maps Example

This example will build on the example in the Using Data Types
tutorial. That tutorial walks you through storing CMS-style user data in
Riak maps, and we’d suggest that you
familiarize yourself with that tutorial first. More specifically, user
data is stored in the following fields in each user’s map:

first name in a first_name register

last name in a last_name register

whether the user is an enterprise customer in an enterprise_customer
flag

the number of times the user has visited the company page in a
page_visits counter

a list of the user’s interests in an interests set

First, let’s create and activate a bucket type simply called maps that
is set up to store Riak maps:

Searching Counters Within Maps

We now have two maps stored in Riak that we can query. Let’s query to
see how many users have page visit counters above 15. Unlike the
counters example above, we have to specify which counter we’re
querying:

// Using the same method explained above, just changing the query:
String query = "page_visits_counter:[15 TO *]";
// Again using the same method from above:
int numberFound = results.numResults(); // 1

As expected, one of our two stored maps has a page_visits counter
above 15. Let’s make sure that we have the right result:

// Using the same method from above:
String query = "page_visits_counter:[15 TO *]";
// Again using the same method from above:
String registerValue =
results.getAllResults().get(0).get("first_name_register").get(0); // Joan

Querying maps within maps involves construct queries that separate the
different levels of depth with a single dot. Here’s an example query for
finding maps that have a name register embedded within an alter_ego
map:

// Using the same method from above:
String query = "alter_ego_map.name_register:*";
// Again using the same method from above:
int numberFound = results.numResults(); // 2

Once we know how to query embedded fields like this, we can query those
just like any other. Let’s find out which maps have an alter_ego
sub-map that contains a name register that ends with PLant, and
display that customer’s first name: