When GraphQL meets a graph database, there is a more convenient way to query data

At the beginning of human beings, nature is a pigeon.

Hello everyone, my name is Chu Huilong (real name online), you can call me Xiaolongren, one after 00. Currently working in backend development.

Today I will bring you a simple DEMO that provides GraphQL query support for NebulaGraph. The reason why it is simple is because I wanted to complete more work before introducing it to you, but last month was too busy and next month will be even busier, but I really wanted to give Nebula official prizes for nothing, so I quickly brought them up.

pic1|284x177

Experience NebulaGraphQL

Go to the project address first: https://github.com/Dragonchu/NebulaGraphQL

What is GraphQL

Let’s briefly introduce GraphQL first. The official introduction of https://graphql.cn/ detailed information is very clear. Let me talk about my understanding. GraphQL is not a query language like Cypher, but an API design style that matches REST .

So, strictly speaking, it is not to use GraphQL to query the graph database, but to use a GraphQL-style API to query the graph database, or to encapsulate Cypher. This essential work is the same as writing some passed REST interfaces based on NebulaGraph when you do application development.

API query example

The test dataset used in this article is the official basketballplayer dataset of NebulaGraph https://docs.nebula-graph.io/2.0/basketballplayer-2.X.ngql

For example, if I wanted to "get all information about Kobe by his name", I might use an nGQL statement like this:

LOOKUP ON player WHERE player.name == "Kobe Bryant" YIELD id(vertex) as vertexId | FETCH PROP ON player $-.vertexId YIELD properties(vertex);

Although nGQL is very easy to read, it is incomprehensible to a completely 0-based beginner, and the return value of this statement is unclear, at least there is no way to see the result from the query. The analysis of the return value has always been a pain for many people .

So, let's see what happens when we query the same scenario using GraphQL.

The query statement would be:

{
	players(name:"Kobe Bryant"){
		name
		age
	}
}

The returned result is:

{
	players=[{name=Kobe Bryant, age=40}]
}

Look at this elegant query and returned results, I don't think I'll say much, everyone can understand it. it's really

pic2|220x230

In fact, so much has been said above, which is the official summary of GraphQL: describe your data, request the data you want, and get predictable results .

The above query has been implemented in NebulaGraphQL , and it also supports querying data through VertexID (well, I also implemented these two).

A simple introduction to NebulaGraphQL

NebulaGraphQL is a Java library designed to provide the application layer with the ability to query data in the NebulaGraph graph database using GraphQL syntax .

It is very simple to use NebulaGraphQL in the project, because NebulaGraphQL itself only wants to be a simple tool library. If you want to directly integrate into the MVC framework in the future, you may start another project like NebulaGraphQL-Spring (in the picture...). So the use of NebulaGraphQL is almost exactly the same as that of nebula-java.

Example usage:

//创建一个config
GraphqlSessionPoolConfig graphqlSessionPoolConfig = new GraphqlSessionPoolConfig(
                Lists.newArrayList(graphdAddress),
                Lists.newArrayList(metadAddress),
                spaceName, username, password);
//创建一个连接池
GraphqlSessionPool pool = new GraphqlSessionPool(graphqlSessionPoolConfig);
//执行语句
ExecutionResult executionResult = pool.execute("{players(age:32){name\nage}}");
//获取结果
System.out.println(executionResult.getData().toString());

In fact, GraphSessionPoolthe SessionPool of nebula-java is used internally, and all configurations are consistent with the connection pool provided by the official, the only difference is that an additional connection address of metad needs to be provided. This is because NebulaGraphQL automatically builds Schema through metad, and NebulaGraphQL will automatically create Schema when creating a connection pool.

Implementation of NebulaGraphQL

NebulaGraphQL is mainly implemented based on graphql-java . With graphql-java, you can define your own GraphQL Schema according to your project. However, NebulaGraphQL wants to provide some common functions as much as possible, and it must be automatically built according to NebulaGraph's Schema.

When creating GraphqlSessionPool, NebulaGraphQL constructs metadata information in NebulaGraph into GraphQL Schema information by connecting NebulaGraphQL metad. This part is the key problem. Currently, I just do the following transformations:

  1. For all tags in NebulaGraph, a corresponding GraphQL queryable object will be constructed.
  2. Each Tag will have a query with the same name to get information by ID. For example, for the player tag, a query player will be generated. The parameter of this query is vertexID, and the information will be obtained according to the vertexID.
  3. Each Tag will have a -squery appended to the name. For example, for the player tag, a query players will be generated, and the parameters of this query are arbitrary attributes. If there are attributes such as age, name, and country on the player, any combination of these three attributes can be passed in the query parameters. NebulaGraphQL will construct these parameters with "AND" semantics when querying, and then obtain the relevant vertices AND. For parameters not specified by the user, the default is null (this is a known problem, if the purpose is to check null, there will be problems).

Schema example of automatically generated GraphQL on the test dataset:

type Query {
 player(
 "Vertex ID"
 ID: ID
): player
players(age: Int = null, name: String = null): [player]!
team(
"Vertex ID"
ID: ID
): team
 teams(name: String = null): [team]!
}
type player {
age: Int
name: String
}
type team {
name: String
}

Briefly explain, Query is the query entry of GraphQL, in which player, players, team, teams are all automatically generated queries, which can be used as query statements.

The player is queried according to the VertexID and returns a player. There is no identifier behind the player !, indicating that the query result may be empty. The players query has two parameters, corresponding to the two attributes age and name of the player tag. The types of these two parameters are mapped from the data type in NebulaGraph to the data type in GraphQL. The default value is null, and the return value is a list. After the list !, it means that a list must be returned, but there is no !identifier after the player, which means that an empty list may be returned.

Using the players query, the parameter can specify age or name, or age and name together.

The following two types of player and team indicate what attributes these two objects have. You can specify the returned attributes when querying, and NebulaGraphQL will only provide the attributes required by the query when returning results.

Each GraphQL query will have a bound DataFetcher object, which implements how to map GraphQL syntax into nGQL statements, and execute interpolation to return results. The returned result will be mapped to a custom object. After using another small tool of mine, NebulaResultBoot , to map the execution result to a custom object, we can implement application layer caching in the future. Of course, there is also a potential problem here: every query requires all attributes of each point and edge to be obtained, and this part needs to be optimized in the future.

Of course, the goal of NebulaGraphQL is not just to simply map nGQL to GraphQL, because GraphQL can more easily support permission management and implement a layer of caching at the application layer through the DataLoader mechanism in addition to the obvious feature of simple query. However, I haven't researched it very thoroughly so far. It would be great if there are big guys who are willing to join in and realize it together.

In order to facilitate everyone's contribution (mainly because I am lazy), the development and testing of NebulaGraphQL has completed part of the containerization. After cloning the code base to the local, you only need to have Docker locally, and then run it in the root directory of the warehouse

docker-compose -f docker-compose.dev.yml up --build

You can see that the test is running automatically, the NebulaGraph cluster will be started locally and the test data will be automatically inserted, and the process will continue to be optimized in the future.

summary

NebulaGraphQL provides a simpler query statement. The structure of this query statement should be directly provided by the front-end. One of the advantages of GraphQL is that it allows the front-end to select the data it needs to avoid "interface hell". Some people may think that this is equivalent to allowing the front-end to directly access the database. Yes, I think this understanding is indeed no problem. This is also the reason why some people oppose GraphQL, but we will not continue the discussion here.

But one potential advantage of using GraphQL is that it makes it easier to integrate graph and relational databases. Of course, if you just use a graph database, then using NebulaGraphQL can at least facilitate some simple data query and testing.

pic3|225x225

I have not experienced the value of NebulaGraphQL in actual production, because it is purely for fun. If you have any ideas, welcome to communicate in the comment area .

RustDesk 1.2: Using Flutter to rewrite the desktop version, supporting Wayland accused of deepin V23 successfully adapting to WSL 8 programming languages ​​​​with the most demand in 2023: PHP is strong, C/C++ demand slows down React is experiencing the moment of Angular.js? CentOS project claims to be "open to everyone" MySQL 8.1 and MySQL 8.0.34 are officially released Rust 1.71.0 stable version is released
{{o.name}}
{{m.name}}

Guess you like

Origin my.oschina.net/u/4169309/blog/10082855