Welcome to Roboy Memory Module documentation!

The goal of the project is to provide Roboy with modern graph-based Knowledge Representation.

Roboy should feature ability to remember information about himself:

  • his name
  • his age
  • his origin
  • his location
  • his friends

etc.

The same is applicable to Roboy speaking about people who are friends with him. Roboy should tell information about a person or an object and be able to provide basic automatic inference (supported by the graph nature of KR). This way, Roboy Memory Module serves as a long-term memory repository of actionable information acquired by other Roboy modules. Persistency layer is presented by a Neo4j graph database.

Upon incoming request, a Java client will pre-process the request and initiate transaction with the database. Two ways of communication between Roboy Java client and Neo4J database are supported: communication using Neo4J driver operating Cypher query language and Neo4J native Java API. Cypher query language offers more flexible querying while communications via Neo4J Java API are implemented as usage-specific routines. Interfaces are implemented on top of ros through the Java client. The input is any type of information Roboy can retrieve from environment abiding by Knowledge Representation reference in format of Roboy Communication Standard protocol, the output are pieces of data related to the requested scope in the same form.

The current main tasks of this project are:

  • Fill the memory in with all possible information about Roboy team
  • Ensure KR retention
  • Improve KR (more powerful inference)
  • Developing an explicit Neo4j ontology
  • Bringing the Memory Module and the Dialog System together

Relevant Background Information and Pre-Requisites

A User should be familiar with:

  • Knowledge Representation theory
  • graph-based KRs
  • Roboy Communication Protocol
  • Roboy Knowledge Representation Architecture

A Developer should be familiar with:

  • graph-based DBs (preferably Neo4j)
  • Knowledge Representation theory
  • Roboy Communication Protocol
  • Roboy Knowledge Representation Architecture
  • Java programming language
  • Maven automation tool
  • rosjava: deprecated

Reading list for a User:

Reading list for a Developer:

Requirements Overview

The software requirements define the system from a blackbox/interfaces perspective. They are split into the following sections:

Contents:

Installation

Maven

The project requires Maven. You may get it here: Download Maven

See also

Consider checking out these entries: Install, Configure and Run

Local Setup

Local Neo4j Instance

There are several options (for a Unix-based OS)

[Recommended] Docker Container Distribution

  • download Docker from apt:

    sudo apt-get install docker.io
    
  • download and run Neo4J via Docker by:

    sudo docker run \
            --publish=7474:7474 --publish=7687:7687 \
            --volume=$HOME/neo4j/data:/data \
            --volume=$HOME/neo4j/logs:/logs \
            neo4j:3.4
    
  • to quit Neo4J, simply CTRL+C or exit the terminal window

Warning

You will be running Neo4J in sudo mode. If you do not wish to do so, see the other methods or here

Using the Debian Repository

  • to use the repository, add it to the list of sources:

    wget -O - https://debian.neo4j.org/neotechnology.gpg.key | sudo apt-key add -
    echo 'deb https://debian.neo4j.org/repo stable/' | sudo tee /etc/apt/sources.list.d/neo4j.list
    sudo apt-get update
    
  • install the latest Neo4j version:

    sudo apt-get install neo4j
    
  • cd into /usr/bin and run:

    neo4j start
    

RPM repository

Follow these steps as root:

  • add the repository:

    rpm --import http://debian.neo4j.org/neotechnology.gpg.key
    cat <<EOF>  /etc/yum.repos.d/neo4j.repo
    [neo4j]
    name=Neo4j RPM Repository
    baseurl=http://yum.neo4j.org/stable
    enabled=1
    gpgcheck=1
    EOF
    
  • install by executing:

    yum install neo4j-3.2.0-rc3 (or the newer version)
    
  • cd into /usr/bin and run:

    neo4j start
    

Tarball installation

  • download the latest release from:

    http://neo4j.com/download/
    
  • select the appropriate tar.gz distribution for your platform

  • extract the contents of the archive, using:

    tar -xf <filename>
    
  • refer to the top-level extracted directory as NEO4J_HOME

  • change directory to $NEO4J_HOME

  • run:

    ./bin/neo4j console
    

Build it yourself

  • clone a git project with:

    git clone git@github.com:neo4j/neo4j.git
    
  • in the project directory do:

    mvn clean install
    
  • after building artifacts with Maven do:

    export PATH="bin:$PATH" && make clean all
    
  • cd into packaging/standalone/target and run:

    bin/neo4j start
    

Congratulations! You have started the Neo4j instance!

Local Redis Instance

In order to compile Redis follow this simple steps:

  • get the source code:

    wget http://download.redis.io/redis-stable.tar.gz
    
  • unzip the tarball:

    tar xvzf redis-stable.tar.gz
    
  • navigate to:

    cd redis-stable
    
  • compile:

    make
    

Remote Setup

Remote Neo4j Instance

If the local instance is not necessary, use a remote Neo4j instance by establishing a connection to the Roboy server. Please, refer to Getting started

Remote Redis Instance

If the local instance is not necessary, use a remote Redis instance by establishing a connection to the Roboy server. Please, refer to Getting started

Installing ROS

Deprecated since version 1.1: The project is using rosjava which requires ROS kinetic.

Simple installation (assuming Ubuntu 16.04 LTS):

  • setup your sources.list:

    sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" >
    /etc/apt/sources.list.d/ros-latest.list'
    
  • set up your keys:

    sudo apt-key adv --keyserver hkp://ha.pool.sks-keyservers.net:80
    --recv-key 421C365BD9FF1F717815A3895523BAEEB01FA116
    
  • update Debian package index:

    sudo apt-get update
    
  • commence desktop full installation of kinetic:

    sudo apt-get install ros-kinetic-desktop-full
    

If the simple installation was not successful, please, refer to this guide.

Roboy Memory Package Installation

The project is implemented upon a build automation tool - Maven, so the dependencies are tracked automatically, if there is a dependency missing or dependency related exception, please leave a feedback at the GitHub repository.

  • clone a git project with:

    git clone git@github.com:Roboy/roboy_memory.git
    

Getting started

Local Instances

Local Neo4j Instance

Before proceeding further, please commence a user configuration step:

  • please navigate inside the package folder $ROBOY_MEMORY to:

    cd scripts
    
  • run:

    ./user_conf.sh -u your_username -p your_password
    
  • wait the script to execute.

You may proceed with your current DB now (you need to put the data there) or fetch the remote DB contents.

To copy remote Neo4j DB into your local instance:

  • open the script intext editor:

    vi backup.sh OR nano backup.sh
    
  • enter the password to connect to bot.roboy.org into respective line

  • run the script specifying the path where to copy the DB files:

    ./backup.sh
    
  • wait the script to execute. You will find the DB in ~/Neo4J/Backups/”date” (if it didn’t work automatically, then create the ~/Neo4J/Backups/ directory and try again)

  • copy the contents of “databases” directory to your local DB directory.

Warning

Be cautious! This procedure (unlikely) might overwrite your credentials with the remote ones, see below.

Local Redis Instance

In order to have Redis properly configured, go through the next steps:

  • create a directory where to store your Redis config files and your data:

    sudo mkdir /etc/redis
    sudo mkdir /var/redis
    
  • copy the template configuration file you’ll find in the root directory of the Redis distribution:

    sudo cp redis.conf /etc/redis/6379.conf
    
  • create a directory that will work as data and working directory:

    sudo mkdir /var/redis/6379
    
  • in the configuration file: set the pidfile to /var/run/redis_6379.pid, set the logfile to /var/log/redis_6379.log, set the dir to /var/redis/6379

Before proceeding further, please commence a password configuration step:

  • please navigate to Redis configuration:

    cd /etc/redis/
    
  • open configuration file with a text editor:

    vi 6379.conf OR nano 6379.conf
    
  • find the line conatining ‘requirepass’, uncomment it and enter your password:

    requirepass some_passphrase
    
  • save and start Redis with the updated configuration:

    ./redis-server /etc/redis/6379.conf
    

Remote Instance

Warning

Be careful while using remote and/or interacting with bot.roboy.org server! You are responsible to keep it functioning properly!

Please, do not crush everything. You would make little kittens very sad.

Remote Neo4j Instance

To use a remote intance of Neo4j containing the most recent Knowledge Representation, ensure your connectivity to the Roboy server. If the server is up, use the roboy_memory package in the remote mode (default):

  • bolt://bot.roboy.org:7687 - for the package configuration (enter this in config file)
  • http://bot.roboy.org:7474 - for the GUI access in web-browser

For this, please use a remote Neo4j password related to your specific user:

  • user, a generic Roboy member
  • dialog, a dialog team member
  • vision, a vision team member
  • memory, a memory team member (developer)
Remote Redis Instance

To use a remote instance of Redis containing the most recent faces features, ensure your connectivity to the Roboy server. If the server is up, use the roboy_memory package in the remote mode (default):

  • redis://bot.roboy.org:6379/0 - for the package configuration

For this, please use the remote Redis password.

ROS Configuration

Deprecated since version 1.1: Using of ROS is deprecated.

Before you can use ROS, you will need to initialize rosdep:

sudo rosdep init
rosdep update

To install dependencies for building ROS packages, run:

sudo apt-get install python-rosinstall python-rosinstall-generator python-wstool build-essential

Afterwords, procceed with installing catkin:

sudo apt-get install ros-kinetic-catkin

Source the environment like this:

echo "source /opt/ros/kinetic/setup.bash" >> ~/.bashrc
source ~/.bashrc

Build a catkin workspace:

mkdir -p ~/catkin_ws/src
cd ~/catkin_ws/
catkin_make

Source your new setup.*sh file:

source devel/setup.bash

Then in separate Terminal, run:

roscore

If you are using Memory Module on the PC other then one with roscore, ROS interfaces require network setup.

For this two variables in Config class (util folder of the Memory Module) should be changed:

  • ROS_MASTER_URI - defines an URI of roscore module in the network, e.g. “http://bot.roboy.org:11311/
  • ROS_HOSTNAME - defines the IP address of the machine with rosjava mudule in the network, e.g. “192.168.1.1”

If you running ros in a virtual machine, please configure bridged networking and use the respective IP addresses:

Running the Package

After you have entered the proper configuration:

  • in the project directory do:

    mvn clean install
    
  • navigate to:

    cd target
    
  • run the package:

    java -jar roboy_memory-1.1.0-jar-with-dependencies.jar
    

Configuring the Package’s Environment Variables

In the configuration file you will encounter the next important fields:

public final static String ROS_MASTER_URI
public final static String ROS_HOSTNAME
public final static String NEO4J_ADDRESS
public final static String NEO4J_USERNAME
public final static String NEO4J_PASSWORD
public final static String REDIS_URI
public final static String REDIS_PASSWORD

Deprecated since version 1.1: ROS_MASTER_URI and ROS_HOSTNAME

For using roboy_memory package in remote mode properly, please initialize specific environment variables. To do so, open your bash profile file with text editor (depending on your preferences):

vi ~/.bashrc OR vi ~/.bash_profile OR nano ~/.bashrc OR nano ~/.bash_profile

and append the next lines with the information specified for you:

export ROS_MASTER_URI="***"
export ROS_HOSTNAME="***"
export NEO4J_ADDRESS="***"
export NEO4J_USERNAME="***"
export NEO4J_PASSWORD="***"
export REDIS_URI="***"
export REDIS_PASSWORD="***"

Deprecated since version 1.1: ROS_MASTER_URI and ROS_HOSTNAME

You may use either remote or local addresses and credentials.

Local Address Example

export ROS_MASTER_URI="http://127.0.0.1:11311"
export ROS_HOSTNAME="127.0.0.1"
export NEO4J_ADDRESS="bolt://127.0.0.1:7687"
export NEO4J_USERNAME="neo4j"
export NEO4J_PASSWORD="neo4jpassword"
export REDIS_URI="redis://localhost:6379/0"
export REDIS_PASSWORD="root"


Development

For further development we recommend using Intellij IDEA IDE. The community edition is available here: Download IDEA.

If you are eligible, we suggest applying for this package containing the full versions of JetBrains software for free.

Using roboy_memory

Availible Operations

The Roboy Memory Module offers the following functions, that will interact with the Neo4J memory:

  • create - creates a node in the Neo4j DB with provided properties and face features (Redis)
  • update - adds new relationships between specified nodes or properties to the specified node
  • get - retrieves information about the specified node or returns IDs of all nodes which fall into the provided conditions
  • remove - removes properties or relationships from the specified node

One can access these features either by calling them directly in org.roboy.memory.util.MemoryOperations or by calling them via ROS, the later being deprecated and highly discouraged to use.

Additionally, there is also support for the Cypher Query Language, which one can read about here

Using Direct Function calls

One can now simply call the functions:

create(String request)
update(String request)
get(String request)
remove(String request)

These functions are located in org.roboy.memory.util.MemoryOperations and can be called, as long as a NEO4J is running at the points specified in your environmental variables (see getting started).

The functions take JSON-formed queries as parameters. There is no need for a header in this case, all one needs to do is to send the payload.

Create queries

Create a node of the type ‘Person’ with properties:

MemoryOperations.create("{'type':'node','label':'Person','properties':{'name':'Lucas','sex':'male'}}");

On success you will get:

Answer: {‘id’: x } - //ID of the created node

On error you will get:

Error: {status:”FAIL”, message:”error message”}

You can find detailed information in Public Interfaces (ROS)

Update queries

Add properties to the node with id 15:

MemoryOperations.update("{ 'type':'node', 'id':15, 'properties':{ 'surname':'Ki', 'xyz':'abc' } }");

Add relationships to the node with id 15:

MemoryOperations.update("{'type':'node','id':15,'relationships':{'LIVE_IN':[28,23],'STUDY_AT':[16]}}"

Add properties + relationships to the node with id 15:

"{'type':'node','id':15,'properties':{'surname':'Ki', 'xyz':123},'relationships':{'LIVE_IN':[28,23],'STUDY_AT':[16]}}"

On success you will get:

Answer: {status:”OK”}

On error you will get:

Error: {status:”FAIL”, message:”error message”}

You can find detailed information in Public Interfaces (ROS)

Get queries

Get properties and relationships of a node by id:

MemoryOperations.get("{'id':15}");

Answer::

{
    'id': 15,
    'labels': ["person"],
    'properties': {
        "birthdate":"01.01.1970",
        "surname":"ki",
        "sex":"male",
        "name":"lucas"
    },
    'relationships': {
        "from":[28],
        "friend_of":[124, 4, 26, 104, 106, 71, 96, 63],
        "member_of":[20], "study_at":[16], "is":[17],
        "has_hobby":[18],
        "live_in":[23, 28]
    }
}

Get ids of nodes which have all specified labels, relationships and/or properties:

MemoryOperations.get("{'label':'Person','relationships':{'FRIEND_OF':[15]},'properties':{'name':'Laura'}}");

On success you will get:

Answer: {‘id’:[x]} - an array with all fitting IDs

On error you will get:

Error: {status:”FAIL”, message:”error message”}

You can find detailed information in Public Interfaces (ROS)

Remove queries

Warning

Please, do not try running remove queries without considering significant risks. Be responsible!

Remove properties of node 15:

MemoryOperations.remove("{'type':'node','id':15,'properties':['birthdate','surname']}");

Remove relationships of node 15:

MemoryOperations.remove("{'type':'node','id':15,'relationships':{'LIVE_IN':[28,23],'STUDY_AT':[16]}}");

Remove properties and relationships of node 15:

MemoryOperations.remove("{'type':'node','id':15,'properties':['birthdate','surname'],'relationships':{'LIVE_IN':[23]}}");

On success you will get:

Answer: {status:”OK”}

On error you will get:

Error: {status:”FAIL”, message:”error message”}

Using ROS

Deprecated since version 1.1: Using ROS is deprecated

There you can find basic examples on how to access the memory with JSON-formed queries using ROS. For more information, please, refer to Public Interfaces (ROS), Neo4j Memory Architecture and Roboy Communication Standard.

To start the ROS services, simply run the Main class’ Main method.

Verifying ROS services are active

In order to check available services, in your catkin environment, run:

rosservice list

You should get the next output:

/roboy/cognition/memory/create
/roboy/cognition/memory/cypher
/roboy/cognition/memory/get
/roboy/cognition/memory/remove
/roboy/cognition/memory/update
/rosout/get_loggers
/rosout/set_logger_level
Calling the ROS

General syntax for a ROS message:

rosservice call /roboy/cognition/memory/--service_name-- "\"---header---\"" "\"---payload---\""

Sample Header:

The header (JSON object) consists of a timestamp and the module which is sending the query (‘user’): You may try using the next header for your initial experience.

{
    'user':'test',
    'datetime':'0'
}

Payload Elements:

The payload (JSON object) may comprise several elements such as:

  • ‘label’ specifies the class of node in the knowledge graph
  • ‘id’ of a node is a unique number specified for each node that may be accessed be searched or modified in the knowledge graph
  • ‘relationships’ comprise a map of relationship types with an array of node IDs for each of them, providing multiple relationships tracing
  • ‘properties’ = A map of property keys with values

Consider Roboy Communication Standard for the correct use use of properties, relationships and labels. Sample payloads as well as the whole structure of the calls are mentioned below.

Create queries

Create a node of the type ‘Person’ with properties:

rosservice call /roboy/cognition/memory/create "\"{
    'user':'vision',
    'datetime':'1234567'
}\"" "\"{
    'type':'node',
    'label':'Person',
    'properties':{
        'name':'Lucas',
        'sex':'male'
    }
}\""

On success you will get:

Answer: {‘id’: x } - //ID of the created node

On error you will get:

Error: {status:”FAIL”, message:”error message”}

You can find detailed information in Public Interfaces (ROS)

Update queries

Add properties to the node with id 15:

rosservice call /roboy/cognition/memory/update "\"{
    'user':'vision',
    'datetime':'1234567'
}\"" "\"{
    'type':'node',
    'id':15,
    'properties':{
        'surname':'Ki',
        'xyz':'abc'
    }
}\""

Add relationships to the node with id 15:

rosservice call /roboy/cognition/memory/update "\"{
    'user':'vision',
    'datetime':'1234567'
}\"" "\"{
    'type':'node',
    'id':15,
    'relationships':{
        'LIVE_IN':[28,23],
        'STUDY_AT':[16]
    }
}\""

Add properties + relationships to the node with id 15:

rosservice call /roboy/cognition/memory/update "\"{
    'user':'vision',
    'datetime':'1234567'
}\"" "\"{
    'type':'node',
    'id':15,
    'properties':{
        'surname':'Ki', 'xyz':123
    },
    'relationships':{
        'LIVE_IN':[28,23],
        'STUDY_AT':[16]
    }
}\""

On success you will get:

Answer: {status:”OK”}

On error you will get:

Error: {status:”FAIL”, message:”error message”}

You can find detailed information in Public Interfaces (ROS)

Get queries

Get properties and relationships of a node by id:

rosservice call /roboy/cognition/memory/get "\"{
    'user':'vision',
    'datetime':'1234567'
}\"" "\"{
    'id':15
}\""

Answer::

{
    'id': 15,
    'labels': ["person"],
    'properties': {
        "birthdate":"01.01.1970",
        "surname":"ki",
        "sex":"male",
        "name":"lucas"
    },
    'relationships': {
        "from":[28],
        "friend_of":[124, 4, 26, 104, 106, 71, 96, 63],
        "member_of":[20], "study_at":[16], "is":[17],
        "has_hobby":[18],
        "live_in":[23, 28]
    }
}

Get ids of nodes which have all specified labels, relationships and/or properties:

rosservice call /roboy/cognition/memory/get "\"{
    'user':'vision',
    'datetime':'1234567'
}\"" "\"{
    'label':'Person',
    'relationships':{
        'FRIEND_OF':[15]
    },
    'properties':{
        'name':'Laura'
    }
}\""

On success you will get:

Answer: {‘id’:[x]} - an array with all fitting IDs

On error you will get:

Error: {status:”FAIL”, message:”error message”}

You can find detailed information in Public Interfaces (ROS)

Remove queries

Warning

Please, do not try running remove queries without considering significant risks. Be responsible!

Remove properties of node 15:

rosservice call /roboy/cognition/memory/remove "\"{
    'user':'vision',
    'datetime':'1234567'
}\"" "\"{
    'type':'node',
    'id':15,
    'properties':['birthdate','surname']
}\""

Remove relationships of node 15:

rosservice call /roboy/cognition/memory/remove "\"{
    'user':'vision','datetime':'1234567'
}\"" "\"{
    'type':'node',
    'id':15,
    'relationships':{
        'LIVE_IN':[28,23],
        'STUDY_AT':[16]
    }
}\""

Remove properties and relationships of node 15:

rosservice call /roboy/cognition/memory/remove "\"{
    'user':'vision',
    'datetime':'1234567'
}\"" "\"{
    'type':'node',
    'id':15,
    'properties':['birthdate','surname'],
    'relationships':{
        'LIVE_IN':[23]
    }
}\""

On success you will get:

Answer: {status:”OK”}

On error you will get:

Error: {status:”FAIL”, message:”error message”}

You can find detailed information in Public Interfaces (ROS)

Troubleshooting

Possible Common Exceptions

Deprecated since version 1.1: Using ROS is deprecated!

Warning

This page describes deprecated interfaces!

No ROS master connection:

org.ros.internal.node.client.Registrar callMaster
SEVERE: Exception caught while communicating with master.
java.lang.RuntimeException: java.net.ConnectException: Host is down

Check if the roscore master PC is connected to the network or master URI in configuration is stated properly.

No roscore running on ROS master:

org.ros.internal.node.client.Registrar callMaster
SEVERE: Exception caught while communicating with master.
java.lang.RuntimeException: java.net.ConnectException: Connection refused

Check if roscore is up on the master PC or master URI in configuration is stated properly.

Host PC is not reachable from ROS master:

ERROR: Unable to communicate with service [/roboy/cognition/memory/get],
address [rosrpc://127.0.0.1:51734/]

Check if hostname for ROS publisher (current PC) in configuration is stated properly.

No service is running on host from ROS master:

ERROR: transport error completing service call:
unable to receive data from sender, check sender's logs for details.

Check if the package is running and services were successfully published (on current PC).

No Neo4j connection:

Exception in thread "pool-1-thread-16" org.neo4j.driver.v1.exceptions.ServiceUnavailableException:
Unable to connect to 127.0.0.1:7687, ensure the database is running and that there is a working network connection to it.

Check if Neo4j is up and the Neo4j address in configuration is stated properly.

Neo4j credentials are incorrect:

Exception in thread "pool-1-thread-16" org.neo4j.driver.v1.exceptions.AuthenticationException:
The client is unauthorized due to authentication failure.

Check if Neo4j credentials in configuration are stated properly.

No Redis connection:

Exception in thread "pool-1-thread-33" redis.clients.jedis.exceptions.JedisConnectionException:
java.net.UnknownHostException: 127.0.0.1

Check if Redis is up and the Redis address in configuration is stated properly.

Redis credentials are incorrect:

Exception in thread "pool-1-thread-16" redis.clients.jedis.exceptions.JedisDataException:
ERR invalid password

Check if Redis credentials in configuration are stated properly.

Missing parenthesis:

Exception in thread "pool-1-thread-13" com.google.gson.JsonSyntaxException:
java.io.EOFException: End of input at line 1 column 38 path $.datetime

Check JSON “{}” parenthesis in query.

JSON index is present, but value is not:

Exception in thread "pool-1-thread-24" com.google.gson.JsonSyntaxException:
com.google.gson.stream.MalformedJsonException: Expected value at line 1 column 33 path $.properties

Check if any value in JSON query is missing.

JSON query is formed incorrectly:

Exception in thread "pool-1-thread-18" com.google.gson.JsonSyntaxException:
com.google.gson.stream.MalformedJsonException: Unterminated string at line 1 column 9 path $.

Check if JSON is formed properly: quotes, parenthesis. Refer to Roboy Communication Standard

Primitives are initialized with complex types in JSON query:

Exception in thread "pool-1-thread-14" com.google.gson.JsonSyntaxException:
java.lang.IllegalStateException: Expected an int but was BEGIN_ARRAY at line 1 column 8 path $.id

Exception in thread "pool-1-thread-22" com.google.gson.JsonSyntaxException:
java.lang.IllegalStateException: Expected a string but was BEGIN_ARRAY at line 1 column 11 path $.label

Exception in thread "pool-1-thread-22" com.google.gson.JsonSyntaxException:
java.lang.IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 11 path $.label

Check if the JSON query is type valid: JSON array instead of object is recieved. Change the respective values. Refer to Roboy Communication Standard.

Complex types are initialized with primitive types in JSON query:

Exception in thread "pool-1-thread-21" com.google.gson.JsonSyntaxException:
java.lang.IllegalStateException: Expected BEGIN_ARRAY but was STRING at line 1 column 35 path $.properties[0]

Check if the JSON query is type valid: primitive objects instead of JSON arrays are recieved. Change the respective values. Refer to Roboy Communication Standard.

Wrong complex type is applied on initialization in JSON query:

Exception in thread "pool-1-thread-22" com.google.gson.JsonSyntaxException:
java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 11 path $.label

Exception in thread "pool-1-thread-22" com.google.gson.JsonSyntaxException:
java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 11 path $.label

Check if the JSON query is type valid: JSON object instead of JSON array and vice versa are received. Change the respective values. Refer to Roboy Communication Standard.

Context

Deprecated since version 1.1: The Memory Module receives input from other Cognition module in form of ROS messages containing RCS payload which is then parsed internally.

The Memory Module receives input from other Cognition module in form of JSON string containing RCS payload which is then parsed internally. RCS payload contains valid request, otherwise exception would be raised and Memory Module would answer with “FAIL” and error message.

The main output of the Memory Module is either a single piece of data (JSON object) or set of IDs.

The context of Roboy Memory Module illustrated in the following diagram:

Building blocks overview

UML System Context

UML-type context diagram - shows the birds eye view of the system (black box) described by this architecture within the ecosystem it is to be placed in. Shows orbit level interfaces on the user interaction and component scope.

Conventions

We follow the coding guidelines:

Coding Guidelines
Language Guideline Tools
Java https://google.github.io/styleguide/javaguide.html  
Cypher https://neo4j.com/developer/cypher-query-language/  
Redis https://redis.io/commands  

Architecture Constraints

Technical Constraints / Runtime Interface Requirements

Operating System Constraints
Constraint Name Description
Ubuntu => 16.04 Neo4j is much more stable and easier to support on Linux and Ubuntu is the OS of Roboy as well
Programming Constraints
Constraint Name Description
IntelliJ IDEA There were difficulties with importing the project to NetBeans and Eclipse
rosjava Deprecated! Due to using both Java and ros
Java => 1.8.0 Reasonably recent and stable Java release
Neo4j => 3.2.1 Stable and tested in production

Public Interfaces (ROS)

Deprecated since version 1.1: Interfaces to other modules are realized through ROS (rosjava). Currently 5 interfaces (ROS services) have been designed for communication with Memory Module.

Warning

This page describes deprecated interfaces!

ROS Services

All calls are compliant to this general form:

rosservice call /roboy/cognition/memory/---service_name--- "\"---header---\"" "\"---payload---\""
  • create service: Service called to perform a query writing data into Neo4j database.:

    # argument: String header String payload
    # returns: String answer
    
    rosservice call /roboy/cognition/memory/create
    
  • get service: Service called to perform a query reading data from Neo4j database.:

    ## argument: String header String payload
    # returns: String answer
    
    rosservice call /roboy/cognition/memory/get
    
  • update service: Service called to perform a query altering data in Neo4j database.:

    ## argument: String header String payload
    # returns: String answer
    
    rosservice call /roboy/cognition/memory/update
    
  • remove service: Service called to perform a query deleting data from Neo4j database.:

    ## argument: String header String payload
    # returns: String answer
    
    rosservice call /roboy/cognition/memory/remove
    
  • cypher service: Service called to perform any Cypher query in Neo4j database.:

    ## argument: String header String payload
    # returns: String answer
    
    rosservice call /roboy/cognition/memory/cypher
    

For the first 4 services the payload has to be defined according to Roboy Communication Standard.

Payload Elements:

  • ‘label’ specifies the class of node in the knowledge graph
  • ‘id’ of a node is a unique number specified for each node that may be accessed be searched or modified in the knowledge graph
  • ‘relationships’ comprise a map of relationship types with an array of node ids for each of them, providing multiple relationships tracing
  • ‘properties’ = A map of property keys with values

Each of this element is peculiar to respective service payload.

The Cypher service uses a well-formed query in Cypher as the payload, see Cypher Examples.

Responses

Create query provides the following responses.

Success::

{
    'id': x
}

Failure:

  • some properties are not specified properly:

    {
        status:"FAIL",
        message:"no properties"
    }
    
  • when creating a node, the name property is obligatory, name is missing:

    {
        status:"FAIL",
        message:"no name specified in properties : name required"
    }
    
  • trying to create a node with a non-existing label, see Neo4j Memory Architecture:

    {
        status:"FAIL",
        message:"Label 'Xyz' doesn't exist in the DB"
    }
    

Update query provides the following responses.

Success::

{
    status:"OK"
}

Failure:

  • trying to create a relationship with a non-existing type, see Neo4j Memory Architecture:

    {
        status:"FAIL",
        message:"The relationship type 'XYZ' doesn't exist in the DB"
    }
    

Get query provides the following responses.

Success:

  • getting by ID:

    {
        'id': 15,
        'labels': ["person"],
        'properties': {
            "birthdate":"01.01.1970",
            "surname":"ki",
            "sex":"male",
            "name":"lucas"
        },
        'relationships': {
            "from":[28],
            "friend_of":[124, 4, 26, 104, 106, 71, 96, 63],
            "member_of":[20], "study_at":[16], "is":[17],
            "has_hobby":[18],
            "live_in":[23, 28]
        }
    }
    
  • getting IDs:

    {
        'id':[x, y]
    }
    

Remove query provides the following responses.

Success::

{
    status:"OK"
}

User Interfaces

There is a GUI for development purposes provided by Neo4j. In order to invoke the GUI, a user has to run a Neo4j instance, open a browser and go to:

http://localhost:7474

or if using a remote Neo4j instance:

http://85.10.197.57:7474

which is the Roboy server.

_images/neo4j.png

All other parts of the module are provided without GUI and offer interaction on a command line level.

Neo4j Memory Architecture

Architecture of the Neo4j database in remote. Current version: 1.1.0.

_images/dbvisual.png

Visualization of a DB scheme.

Versioning of KR is performed by implementing architecture proposals and evaluating them, upon evaluation the version is fixed and then new proposals are collected. Adding nodes means major ver. X, adding relationships is minor ver. Y, adding properties is patch ver. Z: ver. X.Y.Z.

Node Classes (Labels)

  • Person
  • Robot
  • Organization
    1. Company
    2. University
  • Location
    1. City
    2. Country
    3. Continent
  • Hobby
  • Type
    1. Occupation
  • Object (which Roboy can detect/interact with)

Edge Classes

(Person, Robot : Person, Robot)

  • FRIEND_OF

(Person, Robot : Location)

  • LIVE_IN
  • FROM

(Person : Organization)

  • WORK_FOR
  • STUDY_AT
  • MEMBER_OF

(Person, Robot : Hobby)

  • HAS_HOBBY

(Person, Robot : Object)

  • KNOW

(Object, Robot, Person, Organization : Type)

  • IS

(Organization, Robot : Organization)

  • PART_OF

(Organization, Location : Location)

  • IS_IN

Property Keys

General

Describes non-specific prameters for any node

  • name [string]
  • id [int]

Person

Describes prameters specific to a person

  • surname [string]
  • birthdate [String]
  • sex [string]
  • face_id (facial features) [int]: reference to a face representation.
  • voice_id (voice signature) [int]: reference to a voice signature.
  • conversation_id (Topic (scope) of the last conversation) [int]: reference to a topic marker for the last conversation. It would refer to a word or summary def by Dialog to recall the previous conversation with a person.
  • telegram_id [string]: ID for identifying users on Telegram. Set to local for non-telegram users.

> Note: Telegram_id is currently under development by the BotBoy Team and will likely be renamed in the forseeable future.

Roboy

Describes prameters specific to Roboy

  • birthdate [string]
  • abilities [list of strings]
  • skills [list of strings]

Object

Describes prameters specific to objects

  • color [string]
  • speed [int]
  • price [int]
  • temperature [int]
  • usage [list of strings]

Roboy Communication Standard

Roboy Communication Standard is a proposal on decorating standard ros messages with JSON-like payload.

Create Queries Payload Message

Creating a node:

{
    'label': 'some_label',
    'faceVector': [float, ..., float] // Under consideration, OPTIONAL
    'properties': {
        'prop_a': 'value_a',
        'prop_b': 'value_b'
    }
}

This query requests creating node with label - some_label, prop_a having value_a and prop_b - value_b. The faceVector contains face features for the node with specified label Person (applicable only to nodes of this label).

There the label may be:

  • Person

  • Robot

  • Organization

    1. Company
    2. University
  • Location

    1. City
    2. Country
    3. Continent
  • Hobby

  • Type

  • Occupation

  • Object (which Roboy can detect/interact with)

Properties other than ‘name’ are not required on the creation and may be omitted. Later the node’s properties may be updated by an update query. The query returns the ID of the created node on success. The faceVector is fed into Redis if present. The named properties and allowed values may be found in Neo4j Memory Architecture.

Update Queries Payload Message

Updating a node

{
    'id': 1, //REQUIRED, contains node id

    'relationships':  {
        'rel_a': [2, 3],
        'rel_b': [3]
    }

    'properties': {
        'prop_a': 'value_a',
        'prop_b': 'value_b'
    }
}

This query requests updating node with ID - 1. This query requests creating relationships between two nodes, where the relationships

are e.g. rel_a, the number denotes the ID of the node to where the relationships is following from the current node.

This query requests creating (changing) properties of the node, where the properties may be e.g. prop_a with value value_a.

Warning

You should be aware of the node label.

The query returns the OK message on success. The named properties and allowed values may be found in Neo4j Memory Architecture.

Get Queries Payload Message

Get nodes IDs

{
    'label': 'some_label',

    'relationships': {
        'rel_a': [2],
        'rel_b': [3]
    },

    'properties': {
        'prop_a': 'value'
    }
}

This query requests getting all nodes which have node label - some_label, have relationships rel_a with the node having ID 2 and rel_b with the node of ID 3, as well as having prop_a equal to value. The query returns an array of node IDs on success (may be an empty array if no such nodes exist). The allowed relationships types for each pair of nodes and named properties of nodes may be found in Neo4j Memory Architecture.

Get node by ID

{
    'id': 1
}

This query requests getting all information about a node with respective ID. The query returns a JSON containing all information about the node on success (may be an empty string if no such node exist).

Warning

You should be aware of the node label.

The respective information about what could be returned may be found in Neo4j Memory Architecture.

Remove Queries Payload Message

Remove properties and relationships of the nodes

{
    'id': 1,

    'relationships': {
        'rel_a': [2],
        'rel_b': [3]
    },

    'properties': {
        'prop_a'
    }
}

This query requests removing all respective properties and relationships with regard to the node with ID = 1: relationships rel_a with the node having ID = 2 and rel_b with the node having ID = 3, as well as property prop_a.

Warning

You should be aware of the node label.

The query returns the OK message on success. The named properties and allowed values may be found in Neo4j Memory Architecture.

Cypher Examples

Cypher is a declarative graph query language that allows for expressive and efficient querying and updating of the graph store. Cypher is a relatively simple but still very powerful language. Very complicated database queries can easily be expressed through Cypher. This allows you to focus on your domain instead of getting lost in database access.

Useful Cypher queries related to actual Knowledge Representation (developer)

Create a „location“-node:

CREATE (n:Location {name: "Munich"})

Add a 2nd Lable (Organization) to a Node:

match (n:Company)
set n:Organization
return n

Create a relationship

if relationship type is not existing yet:

MATCH (a:Person),(b:City) WHERE a.name = 'Lucas' AND b.name = 'Frankfurt' CREATE (a)-[r:FROM]->(b) RETURN r

if relationship type is existing::

MATCH (a:Country),(b:Continent) WHERE a.name = 'Germany' AND b.name = 'Europe' Merge (a)-[r:IS_IN]->(b) RETURN r

Delete

all „location“-Nodes:

MATCH (n:Location) DETACH Delete n

a specific Node by ID:

MATCH (n:Person) where ID(n)=13 DELETE n

all relationships from Roboy:

MATCH (n:Robot { name: 'Roboy' })-[r:FRIEND_OF]->() DELETE r

Add Properties:

Match (n:Object {name: 'Ball'})
Set n.color = 'red'
Set n.price_euro = 15
Set n.usage = ["playing", "trowing", "rolling"]
Return n

Show

all nodes with relationships:

MATCH (n) RETURN n;

the database scheme:

CALL db.schema()

API

class Answer

Answer wrapper.

Outputs OK or error messages to ROS.

Public Static Functions

static String org.roboy.memory.util.Answer.ok(String message)

Answer for ROS if no errors were detected.

Return
JSON object {status:”OK”} to ROS
Parameters
  • message: contains the success message with json data

static String org.roboy.memory.util.Answer.error(String message)

Answer for ROS if an error occurred.

Return
JSON object containing status and message
Parameters
  • message: contains the error message according to the obstacle approached

Private Static Attributes

Logger org.roboy.memory.util.Answer.logger = Logger.getLogger(Answer.class.toString())
class Config

Configuration for ROS, Neo4J and Redis Server connectivity.

Public Static Attributes

final String org.roboy.memory.util.Config.ROS_MASTER_URI = System.getenv(“ROS_MASTER_URI”) == null ? “http://localhost:11311/” : System.getenv(“ROS_MASTER_URI”)
final String org.roboy.memory.util.Config.ROS_HOSTNAME = System.getenv(“ROS_HOSTNAME”) == null ? “127.0.0.1” : System.getenv(“ROS_HOSTNAME”)
final String org.roboy.memory.util.Config.NEO4J_ADDRESS = System.getenv(“NEO4J_ADDRESS”) == null ? “bolt://localhost:7687” : System.getenv(“NEO4J_ADDRESS”)
final String org.roboy.memory.util.Config.NEO4J_USERNAME = System.getenv(“NEO4J_USERNAME”) == null ? “neo4j” : System.getenv(“NEO4J_USERNAME”)
final String org.roboy.memory.util.Config.NEO4J_PASSWORD = System.getenv(“NEO4J_PASSWORD”) == null ? “memory” : System.getenv(“NEO4J_PASSWORD”)
final String org.roboy.memory.util.Config.REDIS_URI = System.getenv(“REDIS_URI”) == null ? “redis://localhost:6379/0” : System.getenv(“REDIS_URI”)
final String org.roboy.memory.util.Config.REDIS_PASSWORD = System.getenv(“REDIS_PASSWORD”) == null ? “root” : System.getenv(“REDIS_PASSWORD”)
class

Data model for JSON parser.

Creates objects, that contain the elements of the Create queries.

Public Functions

String [] org.roboy.memory.models.Create.getFace()
boolean org.roboy.memory.models.Create.validate()

Private Members

String [] org.roboy.memory.models.Create.faceVector
class Dictionary

Public Static Attributes

final HashSet<String> org.roboy.memory.util.Dictionary.LABEL_VALUES

= new HashSet<String>(Arrays.asList(

“Person”,

“Robot”,

“Company”,

“University”,

“City”,

“Country”,

“Hobby”,

“Occupation”,

“Object”,

“Location”,

“Organization”))

final HashSet<String> org.roboy.memory.util.Dictionary.RELATIONSHIP_VALUES

= new HashSet<String> (Arrays.asList(

“FRIEND_OF”,

“LIVE_IN”,

“FROM”,

“WORK_FOR”,

“STUDY_AT”,

“MEMBER_OF”,

“HAS_HOBBY”,

“KNOW”,

“IS”,

“PART_OF”,

“IS_IN”,

“OCCUPIED_AS”,

“CHILD_OF”,

“SIBLING_OF”))

class

Data model for JSON parser.

Creates objects, that contain the elements of the Get queries.

Public Functions

boolean org.roboy.memory.models.Get.validate()
class Header

Data model for JSON parser.

Creates objects, that contain the elements of the Header.

Public Functions

String org.roboy.memory.models.Header.getUser()

Private Members

String org.roboy.memory.models.Header.user
class Main

Public Static Functions

static void org.roboy.memory.Main.main(String[] args)

Private Static Attributes

Logger org.roboy.memory.Main.logger = Logger.getLogger(Main.class.toString())
class MemoryOperations

This class replicates the behaviour of ros.ServiceLogic.

We make use of the exact same functions, just refactored to not be Services.

Public Static Functions

static String org.roboy.memory.util.MemoryOperations.create(String request)

Create a node.

Return
JSON containing the ID of the new node
Parameters
  • request: Query with data regarding the node. Ex: {“labels”:[“Organization”],”label”:”Organization”,”properties”:{“name”:”korn”}}

static String org.roboy.memory.util.MemoryOperations.get(String request)

Get the Node ID.

Return
JSON containing ID of node
Parameters
  • request: Query to specify Node to get. Ex: {“labels”:[“Person”],”label”:”Person”,”properties”:{“name”:”davis”}}

static String org.roboy.memory.util.MemoryOperations.update(String request)

Update Nodes.

Return
JSON establishing whether or not the connection was made or not
Parameters
  • request: Query to link two nodes together. Ex: {“labels”:[“Person”],”label”:”Person”,”properties”:{“name”:”davis”},”relationships”:{“FROM”:[369]},”id”:368}

static String org.roboy.memory.util.MemoryOperations.cypher(String request)

Cypher Method that is never called TODO: Implement this feature or refactor it out, it’s kind of here because there was a service.

Return
Parameters
  • request:

static String org.roboy.memory.util.MemoryOperations.delete(String request)

This method should contain the code of remove, to make things consistent. See SDE-60

static String org.roboy.memory.util.MemoryOperations.remove(String request)

Delete a Node.

Return
Whether or not deleting was successful or not
Parameters
  • request: JSON query to delete a specified node. Ex: {‘type’:’node’,’id’:361,’properties_list’: [‘sex’], ‘relationships’:{‘FRIEND_OF’:[426]}}

Private Static Attributes

Gson org.roboy.memory.util.MemoryOperations.parser = new Gson()
class Neo4j : public AutoCloseable

Contains the methods for running GET, CREATE, UPDATE, REMOVE and Cypher queries.

Talks to the Neo4j and Redis databases. Handles the result retrieved from Neo4j.

Public Functions

void org.roboy.memory.util.Neo4j.close()

Public Static Functions

static Driver org.roboy.memory.util.Neo4j.getInstance()

Singleton for the Neo4j class.

Return
Neo4J Driver instance if the object of Neo4j class is initialized

static Value org.roboy.memory.util.Neo4j.parameters(Object... keysAndValues)

Wrapper for the Neo4j query parameters.

Return
Set of keys and values for parameters

static String org.roboy.memory.util.Neo4j.run(String query)

Method to channel a plain Cypher query to Neo4j.

Return
plain response from Neo4j
Parameters
  • query: formed in Cypher

static String org.roboy.memory.util.Neo4j.createNode(Create create)

Method accepting JSON Create queries.

Return
result obtained by createNode method

static String org.roboy.memory.util.Neo4j.updateNode(Update update)

Method accepting JSON Update queries.

Return
result obtained by update method

static String org.roboy.memory.util.Neo4j.getNodeById(int id)

Method accepting JSON Get by ID queries.

Return
result obtained by matchNodeById method
Parameters
  • id: is a unique pointer to the node in Neo4j DB

static String org.roboy.memory.util.Neo4j.getNode(Get get)
static String org.roboy.memory.util.Neo4j.remove(Remove remove)

Method accepting JSON Remove queries.

Return
result obtained by removeRelsProps method

Private Functions

org.roboy.memory.util.Neo4j.Neo4j()
Driver org.roboy.memory.util.Neo4j.getDriver()

Getter for the Neo4j driver instance.

Return
Neo4J Driver instance

Private Static Functions

static String org.roboy.memory.util.Neo4j.createNode(Session session, Create create)

Method processing JSON Create queries.

Return
ID of the node that was created in Neo4j DB
Parameters
  • session: is a session handler for transaction handling to query Neo4j DB

static void org.roboy.memory.util.Neo4j.saveToJedis(String[] face, String id)
static String org.roboy.memory.util.Neo4j.update(Transaction tx, Update update)

Method processing JSON Update queries.

Return
response from Neo4j upon updating the node
Parameters
  • tx: is a transaction handler to query Neo4j DB

static String org.roboy.memory.util.Neo4j.matchNodeById(Transaction tx, int id)

Method processing JSON Get by ID queries.

Return
a JSON object containing node labels, properties and relationships
Parameters
  • tx: is a transaction handler to query Neo4j DB
  • id: is a unique pointer to the node in Neo4j DB

static int [] org.roboy.memory.util.Neo4j.toIntArray(List< Integer > list)
static Node org.roboy.memory.util.Neo4j.createNode(int id, HashMap< String, String > properties, HashMap< String, int[]> relationships)
static String org.roboy.memory.util.Neo4j.matchNode(Transaction tx, Get get)
static String org.roboy.memory.util.Neo4j.remove(Transaction tx, Remove remove)

Method processing JSON Remove queries.

Return
response from Neo4j upon removing the specified relationships and properties
Parameters
  • tx: is a transaction handler to query Neo4j DB

Private Static Attributes

Neo4j org.roboy.memory.util.Neo4j._instance
Driver org.roboy.memory.util.Neo4j._driver
Jedis org.roboy.memory.util.Neo4j.jedis
Gson org.roboy.memory.util.Neo4j.gson = new Gson()
Logger org.roboy.memory.util.Neo4j.logger = Logger.getLogger(Neo4j.class.toString())
class Node

Subclassed by org.roboy.memory.models.RosNode

Public Functions

org.roboy.memory.models.Node.Node()
String org.roboy.memory.models.Node.getLabel()
void org.roboy.memory.models.Node.setLabel(String label)
Integer org.roboy.memory.models.Node.getId()
void org.roboy.memory.models.Node.setId(Integer id)
HashMap<String, String> org.roboy.memory.models.Node.getProperties()
void org.roboy.memory.models.Node.setProperties(HashMap< String, String > properties)
HashMap<String, int[]> org.roboy.memory.models.Node.getRelationships()
void org.roboy.memory.models.Node.setRelationships(HashMap< String, int[]> relationships)

Private Members

String org.roboy.memory.models.Node.label
Integer org.roboy.memory.models.Node.id
HashMap<String, String> org.roboy.memory.models.Node.properties
HashMap<String, int[]> org.roboy.memory.models.Node.relationships
class QueryBuilder

Public Functions

org.roboy.memory.util.QueryBuilder.QueryBuilder()
QueryBuilder org.roboy.memory.util.QueryBuilder.add(String text)
QueryBuilder org.roboy.memory.util.QueryBuilder.addParameters(HashMap< String, String > params)
String org.roboy.memory.util.QueryBuilder.getQuery()
QueryBuilder org.roboy.memory.util.QueryBuilder.matchById(int id, String letter)
QueryBuilder org.roboy.memory.util.QueryBuilder.set(HashMap< String, String > properties, String letter)
QueryBuilder org.roboy.memory.util.QueryBuilder.add(String text, Object... args)

Private Members

StringBuilder org.roboy.memory.util.QueryBuilder.builder
class

Data model for JSON parser.

Creates objects, that contain the elements of the Remove queries.

Public Functions

HashSet<String> org.roboy.memory.models.Remove.getPropertiesList()
boolean org.roboy.memory.models.Remove.validate()

Private Members

HashSet<String> org.roboy.memory.models.Remove.properties_list
class

Subclassed by org.roboy.memory.models.Create, org.roboy.memory.models.Get, org.roboy.memory.models.Remove, org.roboy.memory.models.Update

Public Functions

String org.roboy.memory.models.RosNode.getError()
abstract boolean org.roboy.memory.models.RosNode.validate()

Protected Functions

void org.roboy.memory.models.RosNode.error(String text)

Private Members

transient String org.roboy.memory.models.RosNode.error
class RosNode : public AbstractNodeMain

ROS Service for saving data object to DB.

Data is received as JSON object. JSON object is parsed using Parser and saved to neo4j.

Public Functions

GraphName org.roboy.memory.ros.RosNode.getDefaultNodeName()
void org.roboy.memory.ros.RosNode.onStart(ConnectedNode connectedNode)

Initialising the ROS services and setting ROS services URIs.

Parameters
  • connectedNode: is the ROS node carrying the services.

Package Static Functions

static void org.roboy.memory.ros.RosNode.register(NodeConfiguration nodeConfiguration, NodeMainExecutor nodeMainExecutor)

Registers the ROS node.

Parameters
  • nodeConfiguration: is the ROS node configurator
  • nodeMainExecutor: is the ROS node executor

Private Static Attributes

String org.roboy.memory.ros.RosNode.name = “/roboy/cognition/memory”

URI for the ROS node.

class RosRun

This server is responsible for starting ros services.

Public Functions

org.roboy.memory.ros.RosRun.RosRun()

Constructor.

Initializes the ROS node.

void org.roboy.memory.ros.RosRun.start()

Registers the ROS node with services in the network.

void org.roboy.memory.ros.RosRun.stop()

Shutdowns the ROS node and terminates the services.

Private Members

NodeMainExecutor org.roboy.memory.ros.RosRun.nodeMainExecutor

ROS executor.

NodeConfiguration org.roboy.memory.ros.RosRun.nodeConfiguration

ROS node configurator.

class ServiceLogic

Contains service handlers to talk with ROS.

They parse the header and payload and check for invalid elements in the query. Then the functions to construct the cypher queries are excecuted and the answer returned.

Public Static Attributes

ServiceResponseBuilder<DataQueryRequest, DataQueryResponse> org.roboy.memory.ros.ServiceLogic.createServiceHandler

= (request, response) -> {

Header

header = parser.fromJson(request.getHeader(), Header.class);

Create

create = parser.fromJson(request.getPayload(), Create.class);

if (create.validate()) {

if (!create.getLabel().toUpperCase().equals(“OTHER”)) {

response.setAnswer(

Neo4j.createNode

(create));

} else {

response.setAnswer(create.getError());

}

} else {

response.setAnswer(create.getError());

}

}

Create Service Handler.

Parses the header and payload into a create object with Gson and checks for invalid elements in the query. Calls createNode() method to query Neo4j and the answer is returned.

ServiceResponseBuilder<DataQueryRequest, DataQueryResponse> org.roboy.memory.ros.ServiceLogic.updateServiceHandler

= (request, response) -> {

Header

header = parser.fromJson(request.getHeader(), Header.class);

Update

update = parser.fromJson(request.getPayload(), Update.class);

if (update.validate()) {

if (!update.getLabel().toUpperCase().equals(“OTHER”)) {

response.setAnswer(ok(

Neo4j.updateNode

(update)));

} else {

response.setAnswer(error(update.getError()));

}

} else {

response.setAnswer(error(update.getError()));

}

}

Update Service Handler.

Parses the header and payload into an update object with Gson and checks for invalid relationship types in the query. Calls updateNode() method to query Neo4j and the answer is returned.

ServiceResponseBuilder<DataQueryRequest, DataQueryResponse> org.roboy.memory.ros.ServiceLogic.getServiceHandler

= (request, response) ->

{

Header

header = parser.fromJson(request.getHeader(), Header.class);

logger.info(“Request payload: ” + request.getPayload());

Get

get = parser.fromJson(request.getPayload(), Get.class);

if (get.getId() != null ) {

response.setAnswer(

Neo4j.getNodeById

(get.getId()));

} else {

if (!get.getLabel().toUpperCase().equals(“OTHER”)) {

response.setAnswer(Neo4j.getNode(get));

} else {

response.setAnswer(error(get.getError()));

}

}

}

Get Service Handler.

Parses the header and payload into a get object with Gson and checks whether node IDs or information about a node is queried. Calls getNodeById() or getNode() methods to query Neo4j and the answer is returned.

ServiceResponseBuilder<DataQueryRequest, DataQueryResponse> org.roboy.memory.ros.ServiceLogic.cypherServiceHandler

= (request, response) -> {

Header

header = parser.fromJson(request.getHeader(), Header.class);

response.setAnswer(

Neo4j.run

(request.getPayload()));

}

Cypher Service Handler.

Directly runs a plain Cypher query which is contained in the payload and returns the response.

ServiceResponseBuilder<DataQueryRequest, DataQueryResponse> org.roboy.memory.ros.ServiceLogic.removeServiceHandler

= (request, response) -> {

Header

header = parser.fromJson(request.getHeader(), Header.class);

Remove

remove = parser.fromJson(request.getPayload(), Remove.class);

if (remove.validate()) {

response.setAnswer(ok(

Neo4j.remove

(remove)));

} else {

response.setAnswer(error(remove.getError()));

}

}

Remove Service Handler.

Parses the header and payload into a remove object. Calls remove() method to query Neo4j and the answer is returned.

Private Static Attributes

Gson org.roboy.memory.ros.ServiceLogic.parser = new Gson()
Logger org.roboy.memory.ros.ServiceLogic.logger = Logger.getLogger(ServiceLogic.class.toString())
class

Data model for JSON parser.

Creates objects, that contain the elements of the Update queries.

Public Functions

boolean org.roboy.memory.models.Update.validate()
namespace org
namespace v1
namespace roboy
namespace memory
namespace models
namespace ros
namespace util
namespace Config
file Main.java
file Create.java
file Get.java
file Header.java
file Node.java
file Remove.java
file RosNode.java
file RosNode.java
file Update.java
file RosRun.java
file ServiceLogic.java
file Answer.java
file Config.java
file Dictionary.java
file MemoryOperations.java
file Neo4j.java
file QueryBuilder.java
page deprecated

dir /home/docs/checkouts/readthedocs.org/user_builds/roboy-memory/checkouts/develop/src/org/roboy/memory
dir /home/docs/checkouts/readthedocs.org/user_builds/roboy-memory/checkouts/develop/src/org/roboy/memory/models
dir /home/docs/checkouts/readthedocs.org/user_builds/roboy-memory/checkouts/develop/src/org
dir /home/docs/checkouts/readthedocs.org/user_builds/roboy-memory/checkouts/develop/src/org/roboy
dir /home/docs/checkouts/readthedocs.org/user_builds/roboy-memory/checkouts/develop/src/org/roboy/memory/ros
dir /home/docs/checkouts/readthedocs.org/user_builds/roboy-memory/checkouts/develop/src
dir /home/docs/checkouts/readthedocs.org/user_builds/roboy-memory/checkouts/develop/src/org/roboy/memory/util

Solution Strategy

Basic decisions for Memory Module:

  • Separation of concern through decoupling request processing and a persistence layer.
  • Iterative and incremental development is adopted.
  • Highest priority is Knowledge Representation implementation to satisfy the requirements and abilities for Dialog. Roboy Communication Standard is of the second priority as it follows the KR structure. The following priority is providing other modules with actual client and interfaces for the usage.
  • For Knowledge Representation, a graph-based approach was chosen. Thus the persistency layer is presented by Neo4j graph database.
  • Client for request processing is implemented on top of rosjava.

Current implementation:

  • Graph-based Knowledge Representation ver. 1.1.0 on remote server.
  • Redis for face features storage on remote server.
  • Roboy Communication Standard commands pool.
  • Java client software.

Motivation

The motivation to use a graph-based approach was easier (and probably more obvious) maintenance of relations and basic inference contained in graph-models by definition.

Java was the choice for development because it is Neo4j native language, thus has better support.

Redis was chosen as a simple yet powerful and fast (which is important for online face recognition) key-value storage.

Choice of rosjava was forced by both the usage of Java and ros as means of communication between Roboy parts.

Roboy Communication Standard was introduced to make querying more human-readable and graceful.

Java Client Flowchart

Overview

The flowchart shows the process of parsing and processing the queries within the Java client. Query elements that pass the validation are documented on the following page: Neo4j Memory Architecture.

Java client overview

Java client overview

Building Block View

Overview

The white box view of the first level of the code. This is a white box view of the system as shown within the in Context in figure: UML System Context. External libraries and software are clearly marked.

Bulding blocks overview

Building blocks overview

Runtime View

UML-type sequence diagram - Shows how components interact with each other during runtime.

Runtime Scenario 1 - Read person’s name by id

Demo Sequence diagram

Runtime Scenario 2 - Write person’s birthday by id

Demo Sequence diagram

General Sequence Workflow

Sequence Workflow diagram

Deployment View

Deployment diagram shows which part of software runs on which machine or device

Libraries and external Software

Contains a list of the libraries and external software used by this system.

Libraries and external Software
Name URL/Author License Description
junit http://junit.org/junit4/ Eclipse Public License - v 1.0 a simple framework to write repeatable tests
Neo4j driver https://neo4j.com/download/other-releases/#drivers Apache License, v. 2.0 access to the Neo4j graph database through Java
rosjava https://github.com/rosjava/rosjava_core Apache License, v. 2.0 a client library for ros communications in java as well as growing list of core tools (e.g. tf, geometry) and drivers (e.g. hokuyo)
Jedis https://github.com/xetorthio/jedis MIT License a small and sane Redis java client
Gson https://github.com/google/gson Apache License, v. 2.0 a Java serialization/deserialization library to convert Java Objects into JSON and back

About arc42

This information should stay in every repository as per their license: http://www.arc42.de/template/licence.html

arc42, the Template for documentation of software and system architecture.

By Dr. Gernot Starke, Dr. Peter Hruschka and contributors.

Template Revision: 6.5 EN (based on asciidoc), Juni 2014

© We acknowledge that this document uses material from the arc 42 architecture template, http://www.arc42.de. Created by Dr. Peter Hruschka & Dr. Gernot Starke. For additional contributors see http://arc42.de/sonstiges/contributors.html

Note

This version of the template contains some help and explanations. It is used for familiarization with arc42 and the understanding of the concepts. For documentation of your own system you use better the plain version.

Literature and references

Starke-2014
Gernot Starke: Effektive Softwarearchitekturen - Ein praktischer Leitfaden. Carl Hanser Verlag, 6, Auflage 2014.
Starke-Hruschka-2011
Gernot Starke und Peter Hruschka: Softwarearchitektur kompakt. Springer Akademischer Verlag, 2. Auflage 2011.
Zörner-2013
Softwarearchitekturen dokumentieren und kommunizieren, Carl Hanser Verlag, 2012

Examples

Acknowledgements and collaborations

arc42 originally envisioned by Dr. Peter Hruschka and Dr. Gernot Starke.

Sources
We maintain arc42 in asciidoc format at the moment, hosted in GitHub under the aim42-Organisation.
Issues
We maintain a list of open topics and bugs.

We are looking forward to your corrections and clarifications! Please fork the repository mentioned over this lines and send us a pull request!

Collaborators

We are very thankful and acknowledge the support and help provided by all active and former collaborators, uncountable (anonymous) advisors, bug finders and users of this method.

Currently active
  • Gernot Starke
  • Stefan Zörner
  • Markus Schärtel
  • Ralf D. Müller
  • Peter Hruschka
  • Jürgen Krey
Former collaborators

(in alphabetical order)

  • Anne Aloysius
  • Matthias Bohlen
  • Karl Eilebrecht
  • Manfred Ferken
  • Phillip Ghadir
  • Carsten Klein
  • Prof. Arne Koschel
  • Axel Scheithauer