# RedisGears JVM quick start
## Prerequisites
For this quick start, you need:
- A Redis Enterprise cluster with the [RedisGears module and JVM plugin installed](http://redis.io/docs/latest/operate/oss_and_stack/stack-with-enterprise/gears-v1/installing-redisgears#install-redisgears) and [enabled on a database](http://redis.io/docs/latest/operate/oss_and_stack/stack-with-enterprise/gears-v1/jvm/install)
- `redis-cli` with connectivity to a Redis database
## Tutorial
### Create a Maven project
1. Create a new [Maven project](http://maven.apache.org/guides/getting-started/index.html#).
1. Add the following sections to the [pom.xml](http://maven.apache.org/guides/introduction/introduction-to-the-pom.html) file:
```xml
snapshots-repo
http://oss.sonatype.org/content/repositories/snapshots
com.redislabs
gear_runtime
0.0.3-SNAPSHOT
```
1. Add example code for either [batch processing](#batch-processing) or [event processing](#event-processing) to your project's `main` function.
### Build a JAR
Use the Maven command-line tool or an IDE plugin to compile and package your code into a JAR file:
```sh
$ mvn package
```
### Upload the JAR
Upload your JAR file to a node in the Redis Enterprise cluster. You will need to use the destination filepath when you run your code.
### Run RedisGears Java code
Use the `RG.JEXECUTE` command to run your code:
```sh
$ redis-cli -x -h {host} -p {port} RG.JEXECUTE {package.MainClass} < {filepath}/{JAR name}.jar
```
When you use [`GearsBuilder.run()`](http://redis.io/docs/latest/operate/oss_and_stack/stack-with-enterprise/gears-v1/jvm/classes/gearsbuilder/run), `RG.JEXECUTE` runs your code immediately.
However, if you use [`GearsBuilder.register()`](http://redis.io/docs/latest/operate/oss_and_stack/stack-with-enterprise/gears-v1/jvm/classes/gearsbuilder/register), `RG.JEXECUTE` only outputs an `OK` message if it registers successfully. Your registered code will run whenever certain database events occur.
## Example code
You can use these code examples with your own Maven project to try out batch processing or event processing with the RedisGears JVM plugin.
### Batch processing
If you use the [`GearsBuilder.run()`](http://redis.io/docs/latest/operate/oss_and_stack/stack-with-enterprise/gears-v1/jvm/classes/gearsbuilder/run) function within your code, then the functions you add to the pipeline will run exactly once when you use `RG.JEXECUTE` with your JAR file.
The following example calculates the average rating of all restaurant reviews stored in your database.
#### Add data to the database
1. Connect to your database with `redis-cli`:
```sh
$ redis-cli -h -p
```
1. Add a few review hashes to the database with the `HSET` command:
```sh
127.0.0.1:12000> HSET review:1 user "Alex L" message "My new favorite restaurant!" rating 5
(integer) 3
127.0.0.1:12000> HSET review:2 user "Anonymous user" message "Kind of overpriced" rating 2
(integer) 3
127.0.0.1:12000> HSET review:3 user "Francis J" message "They have a really unique menu." rating 4
(integer) 3
127.0.0.1:12000> exit
```
#### Example code
```java
import java.io.Serializable;
import gears.GearsBuilder;
import gears.readers.KeysReader;
import gears.records.KeysReaderRecord;
public class Reviews implements Serializable
{
private static final long serialVersionUID = 1L;
int count; // Total number of reviews
int ratingsSum; // Sum of all review ratings
// Reviews constructor
public Reviews(int count, int ratingsSum) {
this.count = count;
this.ratingsSum = ratingsSum;
}
public static void main(String args[])
{
// Create the reader that will pass data to the pipe
KeysReader reader = new KeysReader();
// Create the data pipe builder
GearsBuilder gb = GearsBuilder.CreateGearsBuilder(reader);
gb.filter(r->{
// Filter out any keys that are not reviews
return r.getKey().startsWith("review:");
}).map(r->{
// Extract the rating field
return r.getHashVal().get("rating");
})
.accumulate(new Reviews(0, 0), (accumulator, record)-> {
// Count the reviews and add up all of their ratings
accumulator.count++;
accumulator.ratingsSum += Integer.parseInt(record);
return accumulator;
}).map(r->{
// Calculate the average rating
return Double.valueOf(((double) r.ratingsSum) / r.count);
});
// Run the data through the pipeline immediately
gb.run();
}
}
```
#### Example output
```sh
$ redis-cli -x -h {host} -p {port} \
RG.JEXECUTE com.domain.packagename.Reviews < /tmp/rgjvmtest-0.0.1-SNAPSHOT.jar
1) 1) "3.6666666666666665"
2) (empty array)
```
### Event processing
If you use the [`GearsBuilder.register()`](http://redis.io/docs/latest/operate/oss_and_stack/stack-with-enterprise/gears-v1/jvm/classes/gearsbuilder/register) function in your code, then the functions you add to the pipeline will run every time a certain database event occurs.
The following example registers a pipeline of functions to automatically update the maximum age every time you add a new person hash to your database.
#### Example code
```java
import gears.GearsBuilder;
import gears.readers.KeysReader;
import gears.records.KeysReaderRecord;
public class App
{
public static void main(String args[])
{
// Create the reader that will pass data to the pipe
KeysReader reader = new KeysReader();
// Create the data pipe builder
GearsBuilder gb = GearsBuilder.CreateGearsBuilder(reader);
// Only process keys that start with "person:"
gb.filter(r->{
return r.getKey().startsWith("person:");
});
// Compare each person's age to the current maximum age
gb.foreach(r->{
String newAgeStr = r.getHashVal().get("age");
int newAge = Integer.parseInt(newAgeStr);
// Get the current maximum age
String maxAgeKey = "age:maximum";
String maxAgeStr = (String) GearsBuilder.execute("GET", maxAgeKey);
int maxAge = 0; // Initialize to 0
if (maxAgeStr != null) {
// Convert the maximum age to an integer
maxAge = Integer.parseInt(maxAgeStr);
}
// Update the maximum age if a new age is higher
if (newAge > maxAge) {
GearsBuilder.execute("SET", maxAgeKey, newAgeStr);
}
});
// Store this pipeline of functions and
// run them when a new person key is added
gb.register(ExecutionMode.SYNC);
// Note: ExecutionMode defaults to ASYNC
// if you call register() without any arguments
}
}
```
#### Example event processing
After you register your code with the `RG.JEXECUTE` command, add some data to the database and check the value of `age:maximum` to verify that it runs correctly.
1. Connect to your database with `redis-cli`:
```sh
$ redis-cli -h -p
```
1. Add a hash that represents a person with `HSET`:
```sh
127.0.0.1:12000> HSET person:1 name "Alex" age 24
(integer) 2
```
1. The current value of `age:maximum` should match Alex's age:
```sh
127.0.0.1:12000> GET age:maximum
"24"
```
1. Add another person with a higher age and then check that `age:maximum` updated automatically:
```sh
127.0.0.1:12000> HSET person:2 name "Morgan" age 45
(integer) 2
127.0.0.1:12000> GET age:maximum
"45"
```
1. Add a person with a lower age and verify that `age:maximum` did not change:
```sh
127.0.0.1:12000> HSET person:3 name "Lee" age 31
(integer) 2
127.0.0.1:12000> GET age:maximum
"45"
```