The reason I started this work is because the Label
used by S2Graph has a strong type system, so I think it will work well with the schema
provided by GraphQL.
To do this, we converted S2Graph Model (Label, Service ...) into GraphLQL schema whenever added (changed).
Assume that hbase is running on localhost.
If the hbase environment is not set up, you can run it with the following command
sbt package target/apache-s2graph-0.2.1-SNAPSHOT-incubating-bin/bin/hbase-standalone.sh start
If hbase is running well, run the following command after cloning the project locally.
GraphiQL
is not directly related to the GraphQL
implementation, but is recommended for convenient queries. Because of the license problem, you should download the file through the following command.
cd s2graphql/src/main/resources/assets wget https://raw.githubusercontent.com/daewon/sangria-akka-http-example/master/src/main/resources/assets/graphiql.html
You can see that the graphiql.html
file is added to the s2graphql/src/main/resources/assets
folder as shown below.
$ls graphiql.html
And let's run http server.
sbt -DschemaCacheTTL=-1 -Dhttp.port=8000 'project s2graphql' '~re-start'
When the server is running, connect to http://localhost:8000
. If it works normally, you can see the following screen.
S2Graph tutorial I have ported the contents of Your first graph
provided by S2Graph based on GraphQL.
http://localhost:8000
.The environment for this example is Mac OS and Chrome. You can get help with schema-based Autocompletion
using the ctrl + space
key.
If you add a label
or service
, etc. you will need to refresh
(cmd + r
) your browser because the schema will change dynamically.
First, we need a name for the new service.
The following POST query will create a service named “KakaoFavorites”.
Request
mutation { Management { createService( name: "KakaoFavorites" compressionAlgorithm: gz ) { object { name } } } }
Response
{ "data": { "Management": { "createService": { "object": { "name": "KakaoFavorites" } } } } }
1.1 And create a `service column`` which is meta information for storing vertex.
The following POST query will create a service column with the age attribute named "user"
Request
mutation { Management { createServiceColumn( serviceName: KakaoFavorites columnName: "user" columnType: string props: { name: "age" dataType: int defaultValue: "0" storeInGlobalIndex: true } ) { isSuccess object { name props { name dataType } } } } }
Response
{ "data": { "Management": { "createServiceColumn": { "isSuccess": true, "object": { "name": "user", "props": [ { "name": "age", "dataType": "int" } ] } } } } }
To make sure the service and service column is created correctly, check out the following.
Since the schema has changed, GraphiQL must recognize the changed schema. To do this, refresh the browser several times.
Request
query { Management { Service(name:KakaoFavorites) { name serviceColumns { name columnType props { name dataType } } } } }
Response
{ "data": { "Management": { "Service": { "name": "KakaoFavorites", "serviceColumns": [ { "name": "user", "columnType": "string", "props": [ { "name": "age", "dataType": "int" } ] } ] } } } }
Next, we will need some friends.
In S2Graph, relationships are organized as labels. Create a label called friends using the following createLabel API call:
Request
mutation { Management { createLabel( name: "friends" sourceService: { KakaoFavorites: { columnName: user } } targetService: { KakaoFavorites: { columnName: user } } consistencyLevel: strong ) { isSuccess message object { name serviceName tgtColumnName } } } }
Response
{ "data": { "Management": { "createLabel": { "isSuccess": true, "message": "Mutation successful", "object": { "name": "friends", "serviceName": "KakaoFavorites", "tgtColumnName": "user" } } } } }
Check if the label has been created correctly
Since the schema has changed, GraphiQL must recognize the changed schema. To do this, refresh the browser several times.
Request
query { Management { Label(name: friends) { name srcColumnName tgtColumnName } } }
Response
{ "data": { "Management": { "Label": { "name": "friends", "srcColumnName": "user", "tgtColumnName": "user" } } } }
Now that the label friends is ready, we can store the friendship data. Entries of a label are called edges, and you can add edges with edges/insert API:
Since the schema has changed, GraphiQL must recognize the changed schema. To do this, refresh the browser several times.
Request
mutation { addEdge( friends: [ {from: "Elmo", to: "Big Bird"}, {from: "Elmo", to: "Ernie"}, {from: "Elmo", to: "Bert"}, {from: "Cookie Monster", to: "Grover"}, {from: "Cookie Monster", to: "Kermit"}, {from: "Cookie Monster", to: "Oscar"}, ] ) { isSuccess } }
Response
{ "data": { "addEdge": [ { "isSuccess": true }, { "isSuccess": true }, { "isSuccess": true }, { "isSuccess": true }, { "isSuccess": true }, { "isSuccess": true } ] } }
Query friends of Elmo with getEdges API:
Request
query { KakaoFavorites { user(id: "Elmo") { friends { to { id } } } } }
Response
{ "data": { "KakaoFavorites": [ { "friends": [ { "to": "Bert" }, { "to": "Ernie" }, { "to": "Big Bird" } ] } ] } }
Now query friends of Cookie Monster:
Request
query { KakaoFavorites { user(id: "Elmo") { friends { to { id } } } } }
Response
{ "data": { "KakaoFavorites": { "user": [ { "friends": [ { "to": { "id": "Ernie" } }, { "to": { "id": "Big Bird" } }, { "to": { "id": "Bert" } } ] } ] } } }
Request
mutation { Management { createLabel( name: "post" sourceService: { KakaoFavorites: { columnName: user } } targetService: { KakaoFavorites: { columnName: user } } consistencyLevel: strong ) { isSuccess message object { name } } } }
Response
{ "data": { "Management": { "createLabel": { "isSuccess": true, "message": "Mutation successful", "object": { "name": "post" } } } } }
Now, insert some posts of the users:
Since the schema has changed, GraphiQL must recognize the changed schema. To do this, refresh the browser several times.
Request
mutation { addEdge( post: [ { from: "Big Bird", to: "www.kakaocorp.com/en/main" }, { from: "Big Bird", to: "github.com/kakao/s2graph" }, { from: "Ernie", to: "groups.google.com/forum/#!forum/s2graph" }, { from: "Grover", to: "hbase.apache.org/forum/#!forum/s2graph" }, { from: "Kermit", to: "www.playframework.com"}, { from: "Oscar", to: "www.scala-lang.org"} ] ) { isSuccess } }
Response
{ "data": { "addEdge": [ { "isSuccess": true }, { "isSuccess": true }, { "isSuccess": true }, { "isSuccess": true }, { "isSuccess": true }, { "isSuccess": true } ] } }
So far, we have designed a label schema for the labels friends and post, and stored some edges to them.+
This should be enough for creating the timeline feature! The following two-step query will return the URLs for Elmo‘s timeline, which are the posts of Elmo’s friends:
Request
query { KakaoFavorites { user(id: "Elmo") { id friends { to { id post { to { id } } } } } } }
Response
{ "data": { "KakaoFavorites": { "user": [ { "id": "Elmo", "friends": [ { "to": { "id": "Ernie", "post": [ { "to": { "id": "groups.google.com/forum/#!forum/s2graph" } } ] } }, { "to": { "id": "Bert", "post": [] } }, { "to": { "id": "Big Bird", "post": [ { "to": { "id": "www.kakaocorp.com/en/main" } }, { "to": { "id": "github.com/kakao/s2graph" } } ] } } ] } ] } } }
Also try Cookie Monster's timeline:
Request
query { KakaoFavorites { user(id: "Cookie Monster") { friends { to { id post { to { id } } } } } } }
Response
{ "data": { "KakaoFavorites": { "user": [ { "friends": [ { "to": { "id": "Oscar", "post": [ { "to": { "id": "www.scala-lang.org" } } ] } }, { "to": { "id": "Kermit", "post": [ { "to": { "id": "www.playframework.com" } } ] } }, { "to": { "id": "Grover", "post": [ { "to": { "id": "hbase.apache.org/forum/#!forum/s2graph" } } ] } } ] } ] } } }
The example above is by no means a full blown social network timeline, but it gives you an idea of how to represent, store and query graph data with S2Graph.