JanusGraph快速入門

筆者由於工作中需要用到圖數據庫,所以花2小時研究了下Janus Graph這個開源項目,下面是一些學習心得,如果後面使用有更多啓發再更新,如有錯誤,歡迎糾正。

學習一門技術最標準的方式是從官網入門:https://docs.janusgraph.org/

然後搞清楚以下問題即可:

  1. 是什麼?爲什麼出現?
  2. 基本原理
  3. 怎麼使用
  4. 再深入理解原理

1.JanusGraph是什麼

本質問題是圖數據庫是什麼?

JanusGraph旨在支持當需要的存儲和計算能力超出了單臺計算機所能提供的範圍的圖處理。 包括對圖數據進行實時遍歷和分析查詢,這是JanusGraph的基本優勢。

關鍵詞是:圖數據、實時遍歷、實時查詢和分析。

事實上,很多數據不再是關係型數據了,比如,人的關係網絡,物聯網,物流、交通等。對這種數據進行查詢就像對樹進行深度或廣度遍歷,只是圖不僅包括樹,更像是森林。

下面是筆者繪製的Janus圖的基本數據組成:https://docs.janusgraph.org/basics/schema/

圖的組成

2.基本原理

2.1.存儲

Janus支持的存儲有

Apache Cassandra
Apache HBase
Oracle Berkeley DB Java Edition

存儲和索引是分開的:

Elasticsearch
Apache Solr
Apache Lucene

以hbase爲例:Janus只支持等值查詢,將索引屬性的值做一個hash,然後分段存儲在多個regionserver,這樣可以避免查詢熱點。

2.2.部署場景

https://docs.janusgraph.org/basics/deployment/
部署
當單獨以Janus Server模式部署時,客戶端與服務器進行交互可以選擇:

  1. HTTP方式
  2. WebSocket方式
  3. 或者2者的組合

3.怎麼使用

查詢
對圖的操作,最頻繁的就是查詢和分析,下面是一個demo項目。

demo

我們採用集成在應用裏的方式,建一個java項目。

導入依賴

    <properties>
        <java.version>1.8</java.version>
        <janusgraph.version>0.5.1</janusgraph.version>
    </properties>

    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.janusgraph/janusgraph-core -->
        <dependency>
            <groupId>org.janusgraph</groupId>
            <artifactId>janusgraph-core</artifactId>
            <version>${janusgraph.version}</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.janusgraph/janusgraph-berkeleyje -->
        <dependency>
            <groupId>org.janusgraph</groupId>
            <artifactId>janusgraph-berkeleyje</artifactId>
            <version>${janusgraph.version}</version>
        </dependency>

        <dependency>
            <groupId>org.janusgraph</groupId>
            <artifactId>janusgraph-driver</artifactId>
            <version>${janusgraph.version}</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.janusgraph/janusgraph-inmemory -->
        <dependency>
            <groupId>org.janusgraph</groupId>
            <artifactId>janusgraph-inmemory</artifactId>
            <version>${janusgraph.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tinkerpop</groupId>
            <artifactId>gremlin-driver</artifactId>
            <version>3.4.6</version>
        </dependency>
    </dependencies>

建立圖

  1. 選擇圖的存儲方式:這裏爲了快速使用,我們基於內存創建
    private static JanusGraph graph;

    @BeforeAll
    static void _1_create_graph_and_init_data() {
        final PropertiesConfiguration configuration = getGanusConfiguration();
        graph = JanusGraphFactory.open(configuration);
        // management = graph.openManagement();

        initSchema();
        initData();
    }

    private static PropertiesConfiguration getGanusConfiguration() {
        final PropertiesConfiguration p = new PropertiesConfiguration();
        p.setProperty("storage.backend", "inmemory");
        return p;
    }    
  1. 初始化schema:就像建表一樣,不過這裏的結構是: 點和邊的label、屬性keyValue
    private static void initSchema() {
//        final VertexLabel vHumanLabel = management.makeVertexLabel("v_human").make();
        final PropertyKey pkName = graph.makePropertyKey("pk_name")
                .dataType(String.class).cardinality(Cardinality.SET).make();

        // 人這個點有一個屬性是姓名
        final VertexLabel vHumanLabel = graph.makeVertexLabel("v_human").make();
        graph.addProperties(vHumanLabel, pkName);

        // 婚姻這條邊有一個屬性是結婚年齡, 同時是一個無向邊
        final PropertyKey pkMarriedYear = graph.makePropertyKey("pk_married_year")
                .dataType(Integer.class).cardinality(Cardinality.SINGLE).make();
        final EdgeLabel eWifeLabel = graph.makeEdgeLabel("e_married")
                /*.unidirected()*/.multiplicity(Multiplicity.ONE2ONE).make();
        graph.addProperties(eWifeLabel, pkMarriedYear);

        // 朋友關係,無向,多對多,有一個屬性是好友關係強度
        final PropertyKey pkTight = graph.makePropertyKey("pk_tight")
                .dataType(Double.class).cardinality(Cardinality.SINGLE).make();
        final EdgeLabel eFriendLabel = graph.makeEdgeLabel("e_friend")
                /*.unidirected()*/.multiplicity(Multiplicity.MULTI).make();
        graph.addProperties(eFriendLabel, pkTight);
    }
  1. 導入數據: 這裏插入3個點,3條關係
    private static void initData() {
        final String vHumanLabel = "v_human";
        final String eMarriedLabel = "e_married";
        final String eFriendLabel = "e_friend";
        final String pkMarriedYear = "pk_married_year";
        final String pkName = "pk_name";
        final String pkTight = "pk_tight";
        final Vertex vJimo = graph.addVertex(vHumanLabel);
        vJimo.property(pkName, "Jimo");
        final Vertex vLily = graph.addVertex(vHumanLabel);
        vLily.property(pkName, "Lily");

        final Vertex vHehe = graph.addVertex(vHumanLabel);
        vHehe.property(pkName, "Hehe");

        vJimo.addEdge(eMarriedLabel, vLily, pkMarriedYear, 10);
        vJimo.addEdge(eFriendLabel, vLily, pkTight, 0.5);
        vJimo.addEdge(eFriendLabel, vHehe, pkTight, 0.8);
        // vHehe.addEdge(eFriendLabel, vJimo, pkTight, 0.8);
    }

查詢測試

  1. 遍歷所有點和邊:
    @Test
    void _2_traversal_all() {
        final GraphTraversalSource g = graph.traversal();

        final List<Vertex> vertices = g.V().toList();
        for (Vertex v : vertices) {
            System.out.println(v.label() + ":" + v.property("pk_name"));
        }

        final List<Edge> edges = g.E().toList();
        for (Edge e : edges) {
            final Iterator<Property<Object>> properties = e.properties();
            System.out.print(e.label() + ":");
            while (properties.hasNext()) {
                System.out.print(properties.next() + ",");
            }
            System.out.println();
        }
    }

結果:

v_human:vp[pk_name->Jimo]
v_human:vp[pk_name->Lily]
v_human:vp[pk_name->Hehe]

e_married:p[pk_married_year->10],
e_friend:p[pk_tight->0.8],
e_friend:p[pk_tight->0.5],
  1. 查詢Jimo的朋友和老婆
    @Test
    void _3_query() {
        final GraphTraversalSource g = graph.traversal();

        final Vertex myWife = g.V().has("pk_name", "Jimo").out("e_married").next();
        printVertex(myWife);

        final List<Vertex> jimoFriends = g.V().has("pk_name", "Jimo").out("e_friend").toList();
        System.out.println("Jimo friends:");
        for (Vertex heheFriend : jimoFriends) {
            printVertex(heheFriend);
        }
    }

    private void printVertex(Vertex v) {
        final Iterator<VertexProperty<Object>> ps = v.properties();
        System.out.print(v.label() + ":");
        while (ps.hasNext()) {
            final VertexProperty<Object> property = ps.next();
            System.out.print(property + ",");
        }
        System.out.println();
    }

結果:

v_human:vp[pk_name->Lily],

Jimo friends:
v_human:vp[pk_name->Lily],
v_human:vp[pk_name->Hehe],

關閉圖

    @AfterAll
    static void afterAll() {
        graph.close();
    }

4.深入理解

// TODO 待實現

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章