nebula-contrib / ngbatis

NGBATIS is a database ORM framework base NebulaGraph + spring-boot, which takes advantage of the mybatis’ fashion development, including some de-factor operations in single table and vertex-edge, like mybatis-plus. NGBATIS 是一款针对 NebulaGraph + Springboot 的数据库 ORM 框架。借鉴于 MyBatis 的使用习惯进行开发。https://graph-cn.github.io/ngbatis-docs/
https://nebula-contrib.github.io/ngbatis/
Apache License 2.0
132 stars 42 forks source link
asm graph-database hacktoberfest java mybatis nebula nebula-graph nebulagraph orm springboot

NgBatis


English | 中文

What is NgBatis

NgBatis is a database ORM framework base NebulaGraph + spring-boot, which takes advantage of the mybatis’ fashion development, including some de-factor operations in single table and vertex-edge, like mybatis-plus.

If you prefer JPA, graph-ocean is a good choice.

How it works

See EXECUTION-PROCESS.md

Requirements

Version matching

NgBatis nebula-java JDK Springboot Beetl
1.3.0 3.8.3 8 2.7.0 3.15.10.RELEASE
1.3.0-jdk17 3.8.3 17 3.0.7 3.15.10.RELEASE
1.2.2 3.6.0 8 2.7.0 3.15.10.RELEASE
1.2.2-jdk17 3.6.0 17 3.0.7 3.15.10.RELEASE
1.2.1 3.6.0 8 2.7.0 3.15.10.RELEASE
1.2.0-jdk17 3.6.0 17 3.0.7 3.15.10.RELEASE
1.2.0 3.6.0 8 2.7.0 3.15.10.RELEASE
1.1.5 3.5.0 8 2.7.0 3.1.8.RELEASE
1.1.4 3.5.0 8 2.7.0 3.1.8.RELEASE

SNAPSHOT

NgBatis nebula-java JDK Springboot Beetl
1.2.2-jdk17-SNAPSHOT 3.6.0 17 3.0.7 3.15.10.RELEASE
1.2.2-SNAPSHOT 3.6.0 8 2.7.0 3.15.10.RELEASE

The third-party dependencies may differ within the same snapshot version.

How to use

You could refer to ngbatis-demo in this repo.

nebula:
  ngbatis:
    session-life-length: 300000 # since v1.1.2
    check-fixed-rate: 300000 # since v1.1.2
    # space name needs to be informed through annotations(@Space) or xml(space="test")
    # default false(false: Session pool map will not be initialized)
    use-session-pool: false # since v1.1.2
  hosts: 127.0.0.1:19669, 127.0.0.1:9669
  username: root
  password: nebula
  space: test
  pool-config:
    min-conns-size: 0
    max-conns-size: 10
    timeout: 0
    idle-time: 0
    interval-idle: -1
    wait-time: 0
    min-cluster-health-rate: 1.0
    enable-ssl: false
@SpringBootApplication(scanBasePackages = { "org.nebula", "your.domain"})
public class YourApplication {
    public static void main(String[] args) {
        new SpringApplication(YourApplication.class).run(args);
    }
}

If SpringCloud is used in your project, please use @ComponentScan( basePackages = {"org.nebula.contrib", "your.domain"} ) instead.

Examples

a. The MyBatis fashion(compose nGQL queries)

a.1 Declare the data access interface

package ye.weicheng.ngbatis.demo.repository;

import ye.weicheng.ngbatis.demo.pojo.Person;
import java.util.List;
import java.util.Map;
import java.util.Set;

public interface TestRepository {
    // new features from v1.2.0
    Integer returnAge(@Param("person")Person person);

    Person selectPerson();
    Person selectByPerson(Person person);
    List<Person> selectAgeGt(Integer age);
    List<String> selectListString();
    List<Map> selectPersonsMap();
    Map<String, Object> selectTriple();
}

a.2 The query statments

resource/mapper/TestRepository.xml

<mapper
    namespace=
    "ye.weicheng.ngbatis.demo.repository.TestRepository"
>
    <!-- new features from v1.2.0 start -->
    <nGQL id="include-test-value">
        ${myInt}
    </nGQL>

    <nGQL id="ngql-return-age">
        RETURN @ng.include('include-test-value',{'myInt':age});
    </nGQL>

    <!--
    The same as: 
        RETURN ${person.age};
    You can try extracting more common and meaningful scripts.
    -->
    <select id="returnAge" resultType="java.lang.Integer">
        @ng.include('ngql-return-age',person);
    </select>
    <!-- new features from v1.2.0 end -->

    <select id="selectPerson" resultType="ye.weicheng.ngbatis.demo.pojo.Person">
        match (v:person) return v.person.name as name, v.person.age as age limit 1
    </select>

    <select id="selectAgeGt" resultType="ye.weicheng.ngbatis.demo.pojo.Person">
        MATCH (n: person)
        WHERE n.person.age > $p0
        RETURN n
        LIMIT 100
    </select>

    <select id="selectByPerson" resultType="ye.weicheng.ngbatis.demo.pojo.Person">
        MATCH (n: person)
        WHERE n.person.name == $p0.name
        RETURN n
        LIMIT 100
    </select>

    <select id="selectListString" resultType="java.lang.String">
        match (v:person) return v.person.name as name limit 100
    </select>

    <select id="selectPersonsMap" resultType="java.util.Map">
        match (v:person) return v.person.name as name, v.person.age  as age limit 100
    </select>

    <select id="selectTriple" resultType="java.util.Map">
        MATCH (n: person)-[r: like]->(n2: person)
        RETURN n, r, n2
        LIMIT 100
    </select>

    <!-- 
        More complex `nGQL` may need to be fully tested.
        The two-layer object data structure of the project I am currently using is also satisfying.
        `Path` is not yet supported because it can basically be handled by the `n, r, n2` structure in development.
    -->

</mapper>

b. The MyBatis-plus fashion

b.1 model-vertex

package com.example.model.vertex.Person;

import lombok.Data;
import javax.persistence.Id;
import javax.persistence.Table;

@Data
@Table(name = "person")
public class Person {
    @Id
    private String name;
    private Integer age;
}

b.2 model-edge

package com.example.model.edge.Like;

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.Data;
import javax.persistence.Table;

@Data
@Table(name = "like")
@NoArgsConstructor
@AllArgsConstructor
public class Like {
    private Double likeness;
}

b.3 dao

package com.example.dao;

import org.nebula.contrib.ngbatis.proxy.NebulaDaoBasic;
import com.example.model.vertex.Person;

public interface PersonDao extends NebulaDaoBasic<Person, String>{}

b.4 xml

Note, this is a mandatory requirement.

<mapper
    namespace=
    "com.example.dao.PersonDao"
>
</mapper>

b.5 service

package com.example.service;

import org.nebula.contrib.ngbatis.utils.Page;
import com.example.dao.PersonDao;
import com.example.model.vertex.Person;
import com.example.model.edge.Like;

@Service
public class PersonServiceImpl {

    @Autowired private PersonDao dao;

    public void demos() {
        // Implement two node insertions
        Person tom = new Person();
        tom.setName("Tom");
        dao.insert( tom ); 

        Person jerry = new Person();
        jerry.setName( "Jerry" );
        dao.insert( jerry );

        // Establishing the relationship between two nodes
        Like like = new Like( 0.99999 );
        dao.insertEdge( tom, like, jerry );

        // Find people who like jerry
        String jerryId = jerry.getName();
        List<Person> whoLikeJerry = dao.listStartNodes( Like.class, jerryId );

        // Find the only people who like jerry, Non-Unique Times Error。(Limited to scenarios where there is only one upstream for a given relationship)
        Person tom = dao.startNode( Like.class, jerryId );

        // See the Like relationship between Tom and Jerry
        String tomId = tom.getName();
        Boolean tomLikeJerry = dao.existsEdge( tomId, Like.class, jerryId ); // true
        Boolean jerryLikeTom = dao.existsEdge( jerryId, Like.class, tomId ); // false
        // Poor Tom

        // Find all information by Tom's name
        Person tomDb = dao.selectById( "Tom" );

        // Search by page
        Page<Person> page = new Page<>();
        List<Person> personPage = dao.selectPage( page );
        page.getTotal(); // 2 rows, Tom and Jerry
        Boolean theyAreFamily = page.getRows() == personPage; // true

        // The story always wants to have a good ending
        dao.insertEdge( jerry, like, tom );

        // More base class operations are still under development;Expectations
    }

}

c. Entity Direct Search

c.1 Entity class

c.1.1 Vertex Entity

@Tag(name = "player")
public class Player extends GraphBaseVertex {

  @GraphId(type = IdType.STRING)
  private String id;

  private String name;

  private Integer age;

  ...

}

Specific reference ye.weicheng.ngbatis.demo.pojo.vertex vertex entities under the package sample.

c.1.2 Edge Entity

@EdgeType(name = "serve")
public class Serve extends GraphBaseEdge {

  @Id 
  private Long rank;

  @SrcId 
  private String srcId;

  @DstId 
  private String dstId;

  @Column(name = "start_year")
  private Integer startYear;
  @Column(name = "end_year")
  private Integer endYear;

  ...

}

Specific reference ye.weicheng.ngbatis.demo.pojo.edge edge entities under the package sample.

c.2 The method is now provided

c.2.1 About vertex entity
API 用法说明
queryIdsByProperties() Query a collection of vertex ids for a particular Tag or attribute
queryVertexById() Query a single vertex for a specific vertex Id
queryVertexByTag() Query a collection of vertices for a specific Tag
queryVertexByProperties() Query a collection of vertexes for a specific property
queryAllAdjacentVertex(Class<?>... edgeClass) Query a collection of all neighboring vertexes of a particular vertex, specifying one or more edge types that connect the two vertexes
queryIncomingAdjacentVertex(Class<?>... edgeClass) Query the set of adjacent vertexes in the direction of the incoming edge of a particular vertex, specifying one or more edge types that connect two vertexes
queryOutgoingAdjacentVertex(Class<?>... edgeClass) Query the set of adjacent vertexes in the direction of the edge of a particular vertex, specifying one or more edge types that connect two vertexes
queryNeighborIdsWithHopById(int m, int n, Class<?>... edgeClass) Query a collection of vertex ids within a specified number of hops for a particular vertex, specifying one or more edge types that connect two vertexes
queryConnectedEdgesById(Direction direction) Query the set of all edges associated with a particular vertex, specifying the direction and type of the edge
queryPathFromVertex(Direction direction) Query the collection of all paths associated with a particular vertex, specifying the direction of the edge
queryFixedLengthPathFromVertex(Integer maxHop, Direction direction, Class<?>... edgeClass) Query a set of fixed-length paths from a specific vertex, specifying the maximum number of steps, the direction of the edge, and the type of the edge
queryVariableLengthPathFromVertex(Integer minHop, Integer maxHop, Direction direction, Class<?>... edgeClass) Query a set of variable-length paths from a specific vertex, specifying the minimum number of steps, the maximum number of steps, the direction of the edge, and the type of the edge
queryShortestPathFromSrcAndDst(Integer maxHop, Direction direction, T v2) Query any shortest path from a specific vertex, specifying the number of steps, the direction of the edge, and the end vertex entity
queryAllShortestPathsFromSrcAndDst(Integer maxHop, Direction direction, T v2) Query the set of all shortest paths from this vertex, specifying the number of steps, the direction of the edge, and the end vertex entity
queryVertexCountByTag() Query the number of vertexes for a specific Tag

For specific implementation, see the point entity base class GraphBaseVertex under the org.nebula.contrib.ngbatis.base package.

c.2.2 About edge entity
API 用法说明
queryEdgeByType(Direction direction) Query a set of edges of a specific type and direction
queryEdgeWithSrcAndDstByProperties(T srcVertex, Direction direction, T dstVertex) Query a set of edges for a particular property
queryEdgePropertiesBySrcAndDstId() Query a set of edges for a specific always vertex id
queryEdgeCountByType() Query the number of edges for a specific Type

For specific implementation, see the point entity base class GraphBaseEdge under the org.nebula.contrib.ngbatis.base package.

c.3 test


@Test
public void testVertex(){
    Player srcPlayer = new Player();
    //Query all Player vertices that meet the condition name = "Vince Carter"
    srcPlayer.setName("Vince Carter");
    List<Player> vertices = player.queryVertexByProperties();
}

@Test
public void testEdge(){
    Serve serve = new Serve();
    //Query the Server edge whose starting point ID is player100 and the end point ID is team204.
    serve.setSrcId("player100");
    serve.setDstId("team204");
    Serve edge = serve.queryEdgeWithSrcAndDstByProperties();
    //Query the edges of Serve type and direction "->"
    List<Serve> edges = serve.queryEdgeByType(Direction.NULL);
}

For specific usage examples of each direct inspection method, please refer to the NebulaGraphBasicTests test class in ngbatis-demo.

Upstream projects

Community

License

NGBATIS is under the Apache License, Version 2.0.