1. Introduction
1.介绍
This article is about Neo4j – one of the most mature and full-featured graph databases on the market today. Graph databases approach the task of data modeling with the view that many things in life lend themselves to being represented as a collection of nodes (V) and connections between them called edges (E).
本文是关于Neo4j–目前市场上最成熟、功能最齐全的图形数据库之一。图形数据库在处理数据建模任务时,认为生活中的许多事物都可以表示为节点(V)和它们之间的连接(称为边(E))的集合。
2. Embedded Neo4j
2.嵌入式Neo4j
The easiest way to get started with Neo4j is to use the embedded version in which Neo4j runs in the same JVM as your application.
开始使用Neo4j的最简单方法是使用嵌入式版本,其中Neo4j与您的应用程序在同一JVM中运行。
First, we need to add a Maven dependency:
首先,我们需要添加一个Maven依赖项。
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j</artifactId>
<version>3.4.6</version>
</dependency>
You can check this link to download the latest version.
你可以查看这个链接来下载最新版本。
Next, let’s create a factory:
接下来,让我们创建一个工厂。
GraphDatabaseFactory graphDbFactory = new GraphDatabaseFactory();
Finally, we create an embedded database:
最后,我们创建一个嵌入式数据库。
GraphDatabaseService graphDb = graphDbFactory.newEmbeddedDatabase(
new File("data/cars"));
Now the real action can begin! First, we need to create some nodes in our graph and for that, we need to start a transaction since Neo4j will reject any destructive operation unless a transaction has been started:
现在,真正的行动可以开始了!首先,我们需要在图中创建一些节点,为此,我们需要启动一个事务,因为Neo4j会拒绝任何破坏性的操作,除非已经启动了一个事务。
graphDb.beginTx();
Once we have a transaction in progress, we can start adding nodes:
一旦我们有一个正在进行的交易,我们就可以开始添加节点。
Node car = graphDb.createNode(Label.label("Car"));
car.setProperty("make", "tesla");
car.setProperty("model", "model3");
Node owner = graphDb.createNode(Label.label("Person"));
owner.setProperty("firstName", "baeldung");
owner.setProperty("lastName", "baeldung");
Here we added a node Car with properties make and model as well as node Person with properties firstName and lastName
这里我们添加了一个节点Car,属性为make和model,以及节点Person,属性为firstName和lastName。
Now we can add a relationship:
现在我们可以添加一个关系。
owner.createRelationshipTo(car, RelationshipType.withName("owner"));
The statement above added an edge joining the two nodes with an owner label. We can verify this relationship by running a query written in Neo4j’s powerful Cypher language:
上面的语句添加了一条连接这两个节点的边,并有一个所有者标签。我们可以通过运行一个用Neo4j的强大的Cypher语言编写的查询来验证这种关系。
Result result = graphDb.execute(
"MATCH (c:Car) <-[owner]- (p:Person) " +
"WHERE c.make = 'tesla'" +
"RETURN p.firstName, p.lastName");
Here we ask to find a car owner for any car whose make is tesla and give us back his/her firstName and lastName. Unsurprisingly, this returns: {p.firstName=baeldung, p.lastName=baeldung}
在这里,我们要求为任何品牌为特斯拉的汽车找到一个车主,并给出他/她的名字和姓氏。不出所料,这将返回。{p.firstName=baeldung, p.lastName=baeldung}。
3. Cypher Query Language
3.Cypher查询语言
Neo4j provides a very powerful and pretty intuitive querying language which supports the full range of features one would expect from a database. Let us examine how we can accomplish that standard create, retrieve, update and delete tasks.
Neo4j提供了一个非常强大且相当直观的查询语言,支持人们对数据库所期望的全部功能。让我们来看看我们如何完成那个标准的创建、检索、更新和删除任务。
3.1. Create Node
3.1.创建节点
Create keyword can be used to create both nodes and relationships.
创建关键字可以用来创建节点和关系。
CREATE (self:Company {name:"Baeldung"})
RETURN self
Here we’ve created a company with a single property name. A node definition is marked by parentheses and its properties are enclosed in curly braces. In this case, self is an alias for the node and Company is a node label.
在这里,我们创建了一个具有单一属性name的公司。节点定义由小括号标记,它的属性被括在大括号中。在这种情况下,self是节点的别名,Company是节点标签。
3.2. Create Relationship
3.2.建立关系
It is possible to create a node and a relationship to that node all in a single query:
可以在一个单一的查询中创建一个节点和与该节点的关系。
Result result = graphDb.execute(
"CREATE (baeldung:Company {name:\"Baeldung\"}) " +
"-[:owns]-> (tesla:Car {make: 'tesla', model: 'modelX'})" +
"RETURN baeldung, tesla");
Here we’ve created nodes baeldung and tesla and established an ownership relationship between them. Creating relationships to pre-existing nodes is, of course, also possible.
这里我们创建了节点baeldung和tesla,并在它们之间建立了所有权关系。当然,与预先存在的节点建立关系也是可能的。
3.3. Retrieve Data
3.3.检索数据
MATCH keyword is used to find data in combination with RETURN to control which data points are returned. The WHERE clause can be utilized to filter out only those nodes that have the properties we desire.
MATCH关键字用于查找数据,与RETURN相结合,控制哪些数据点被返回。可以利用WHERE子句,只过滤出那些具有我们想要的属性的节点。
Let us figure out the name of the company that owns tesla modelX:
让我们弄清楚拥有特斯拉modelX的公司的名称。
Result result = graphDb.execute(
"MATCH (company:Company)-[:owns]-> (car:Car)" +
"WHERE car.make='tesla' and car.model='modelX'" +
"RETURN company.name");
3.4. Update Nodes
3.4.更新节点
SET keyword can be used for updating node properties or labels. Let us add mileage to our tesla:
SET关键字可用于更新节点属性或标签。让我们给我们的特斯拉增加里程数。
Result result = graphDb.execute("MATCH (car:Car)" +
"WHERE car.make='tesla'" +
" SET car.milage=120" +
" SET car :Car:Electro" +
" SET car.model=NULL" +
" RETURN car");
Here we add a new property called milage, modify labels to be both Car and Electro and finally, we delete model property altogether.
在这里,我们添加了一个名为milage的新属性,将标签修改为Car和Electro,最后,我们完全删除model属性。
3.5. Delete Nodes
3.5.删除节点
DELETE keyword can be used for permanent removal of nodes or relationships from the graph:
DELETE关键字可用于从图中永久删除节点或关系。
graphDb.execute("MATCH (company:Company)" +
" WHERE company.name='Baeldung'" +
" DELETE company");
Here we deleted a company named Baeldung.
在这里,我们删除了一家名为Baeldung的公司。
3.6. Parameter Binding
3.6.参数绑定
In the above examples, we have hard-coded parameter values which isn’t the best practice. Luckily, Neo4j provides a facility for binding variables to a query:
在上面的例子中,我们硬编码了参数值,这并不是最好的做法。幸运的是,Neo4j提供了一个将变量绑定到查询中的工具。
Map<String, Object> params = new HashMap<>();
params.put("name", "baeldung");
params.put("make", "tesla");
params.put("model", "modelS");
Result result = graphDb.execute("CREATE (baeldung:Company {name:$name}) " +
"-[:owns]-> (tesla:Car {make: $make, model: $model})" +
"RETURN baeldung, tesla", params);
4. Java Driver
4.Java驱动
So far we’ve been looking at interacting with an embedded Neo4j instance, however, in all probability for production, we’d want to run a stand-alone server and connect to it via a provided driver. First, we need to add another dependency in our maven pom.xml:
到目前为止,我们一直在研究如何与嵌入式Neo4j实例进行交互,但在生产中,我们很可能希望运行一台独立的服务器,并通过提供的驱动与之连接。首先,我们需要在maven的pom.xml中添加一个依赖项。
<dependency>
<groupId>org.neo4j.driver</groupId>
<artifactId>neo4j-java-driver</artifactId>
<version>1.6.2</version>
</dependency>
You can follow this link to check for the latest version of this driver.
你可以按照这个链接来检查这个驱动程序的最新版本。
Now we can establish a connection:
现在我们可以建立一个连接。
Driver driver = GraphDatabase.driver(
"bolt://localhost:7687", AuthTokens.basic("neo4j", "12345"));
Then, create a session:
然后,创建一个会话。
Session session = driver.session();
Finally, we can run some queries:
最后,我们可以运行一些查询。
session.run("CREATE (baeldung:Company {name:\"Baeldung\"}) " +
"-[:owns]-> (tesla:Car {make: 'tesla', model: 'modelX'})" +
"RETURN baeldung, tesla");
Once we are done with all our work we need to close both session and the driver:
一旦我们完成了所有的工作,我们需要关闭会话和驱动程序。
session.close();
driver.close();
5. JDBC Driver
5.JDBC驱动程序
It is also possible to interact with Neo4j via a JDBC driver. Yet another dependency for our pom.xml:
也可以通过JDBC驱动与Neo4j互动。这是我们的pom.xml的另一个依赖项。
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-jdbc-driver</artifactId>
<version>3.4.0</version>
</dependency>
You can follow this link to download the latest version of this driver.
你可以按照这个链接来下载这个驱动程序的最新版本。
Next, let’s establish a JDBC connection:
接下来,让我们建立一个JDBC连接。
Connection con = DriverManager.getConnection(
"jdbc:neo4j:bolt://localhost/?user=neo4j,password=12345,scheme=basic");
Here con is a regular JDBC connection which can be used for creating and executing statements or prepared statements:
这里con是一个普通的JDBC连接,可用于创建和执行语句或准备的语句。
try (Statement stmt = con.
stmt.execute("CREATE (baeldung:Company {name:\"Baeldung\"}) "
+ "-[:owns]-> (tesla:Car {make: 'tesla', model: 'modelX'})"
+ "RETURN baeldung, tesla")
ResultSet rs = stmt.executeQuery(
"MATCH (company:Company)-[:owns]-> (car:Car)" +
"WHERE car.make='tesla' and car.model='modelX'" +
"RETURN company.name");
while (rs.next()) {
rs.getString("company.name");
}
}
6. Object-Graph-Mapping
6.对象-图形-映射
Object-Graph-Mapping or OGM is a technique which enables us to use our domain POJOs as entities in the Neo4j database. Let us examine how this works. The first step, as usually, we add new dependencies to our pom.xml:
Object-Graph-Mapping或OGM是一种技术,它使我们能够在Neo4j数据库中使用我们的领域POJOs作为实体。让我们来看看这是如何工作的。第一步,像通常一样,我们在pom.xml中添加新的依赖项。
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-ogm-core</artifactId>
<version>3.1.2</version>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-ogm-embedded-driver</artifactId>
<version>3.1.2</version>
</dependency>
You can check the OGM Core Link and OGM Embedded Driver Link to check for the latest versions of these libraries.
你可以查看OGM核心链接和OGM嵌入式驱动链接,以检查这些库的最新版本。
Second, we annotate our POJO’s with OGM annotations:
其次,我们用OGM注解来注释我们的POJO。
@NodeEntity
public class Company {
private Long id;
private String name;
@Relationship(type="owns")
private Car car;
}
@NodeEntity
public class Car {
private Long id;
private String make;
@Relationship(direction = "INCOMING")
private Company company;
}
@NodeEntity informs Neo4j that this object will need to be represented by a node in the resulting graph. @Relationship communicates the need to create a relationship with a node representing the related type. In this case, a company owns a car.
@NodeEntity通知Neo4j这个对象需要在结果图中由一个节点来表示。@Relationship传达了与代表相关类型的节点创建关系的需求。在本例中,一个公司拥有一辆汽车。
Please note that Neo4j requires each entity to have a primary key, with a field named id being picked up by default. An alternatively named field could be used by annotating it with @Id @GeneratedValue.
请注意,Neo4j要求每个实体都有一个主键,默认情况下,一个名为id的字段被选中。我们可以使用另一种命名的字段,用@Id @GeneratedValue.来注释它。
Then, we need to create a configuration that will be used to bootstrap Neo4j‘s OGM. For simplicity, let us use an embedded in-memory only database:
然后,我们需要创建一个配置,用来引导Neo4j的OGM。为了简单起见,让我们使用一个只在内存中嵌入的数据库。
Configuration conf = new Configuration.Builder().build();
After that, we initialize SessionFactory with the configuration we created and a package name in which our annotated POJO’s reside:
之后,我们用我们创建的配置和我们注释的POJO所在的包名初始化SessionFactory。
SessionFactory factory = new SessionFactory(conf, "com.baeldung.graph");
Finally, we can create a Session and begin using it:
最后,我们可以创建一个Session并开始使用它。
Session session = factory.openSession();
Car tesla = new Car("tesla", "modelS");
Company baeldung = new Company("baeldung");
baeldung.setCar(tesla);
session.save(baeldung);
Here we initiated a session, created our POJO’s and asked OGM session to persist them. Neo4j OGM runtime transparently converted objects to a set of Cypher queries which created appropriate nodes and edges in the database.
在这里,我们启动了一个会话,创建了我们的POJO,并要求OGM会话将它们持久化。Neo4j OGM运行时透明地将对象转换为一组Cypher查询,在数据库中创建适当的节点和边。
If this process seems familiar, that is because it is! That is precisely how JPA works, the only difference being whether object gets translated into rows that are persisted to an RDBMS, or a series of nodes and edges persisted to a graph database.
如果这个过程看起来很熟悉,那是因为它是!这正是JPA的工作方式。这正是JPA的工作方式,唯一的区别是对象是否被转化为持久化到RDBMS中的行,或者是持久化到图数据库中的一系列节点和边。
7. Conclusion
7.结论
This article looked at some basics of a graph-oriented database Neo4j.
这篇文章研究了面向图的数据库Neo4j的一些基础知识。
As always, the code in this write-up is all available over on Github.
一如既往,本篇文章中的代码都可以在Github上找到。