Tigergraph高性能圖數據庫深入調研


TigerGraph圖

 

圖計算

Git開源項目

https://github.com/geektcp/tigergraph-gql

 

概述

圖數據庫目前發展到第三代

第一代以neo4j為代表

第二代以Amazon Neptune為代表

第三代以tigergraph,arangodb為代表

系統架構

 

名詞解釋

基本概念

gadmin:    管理命令,類似mysqladmin

gbar:      備份和存儲命令,backup and resotre

GSQL Shell: 用於執行sql語句,類似mysql數據庫的mysql命令

GraphStudio UI: 可視化控制台

 

 

GPE:圖數據庫計算引擎

Graph Store:    內置的一個基於內存的數據存儲組件

DICT       :   數據分片,類似arangodb的內部的分片機制

GSE :   存儲引擎,GSE通過GPE接收操作數據,對Graph Store進行增刪改查

 

GSQL Language:圖數據庫SQL,類似arangodb的aql

GSQL:      一個內部接口,GSQL Shell調用了這個接口執行圖SQL

HA:    tigergraph支持高可用

IDS:       GSE的內部組件,用於把頂點表、邊表轉換成圖

IUM:       安裝,升級,維護

MultiGraph: 復雜圖架構,支持多個子圖

Native Parallel Graph:並行圖架構,支持並行存儲和分析,高並發,高伸縮性

Nginx       :tigergraph的前端

REST++ or RESTPP:rest api,增加、刪除和查詢,沒有編輯

SSO     :

TigerGraph Platform

TigerGraph System

 

Kakfa

Zookeeper

 

圖查詢計算邏輯

 

 

邊的方向性

tiger的邊分為有向邊,無相邊。

有向邊和無相邊的區別是:界面上有向邊有明顯箭頭,無向邊就是直線。

 

有向邊又有單向邊,雙向邊。

無向邊由於指定了邊的起點類型和終點類型,而任何頂點的類型只能有一個,無所無向邊其實還是有方向的。

 

只有起點和終點類型都是*的時候,才是真正的無向邊。

 

單向邊無法反向遍歷。

 

無相邊和雙向邊都可以反向遍歷。

無向邊的反向遍歷結果相同。

雙向邊的反向遍歷結果中邊的類型不同。

雙向邊和有向邊的本質差別

雙向邊其實無向邊效果差不多。

雙向邊和有向邊的本質差別在於查詢方向。雙向邊可以指定兩個方向查詢,有向邊根本不能反方向查詢。

原因是tiger的查詢語法范式定死了格式。

SELECT t FROM vSetVarName:s – ((eType1|eType2):e) -> (vType1|vType2):t

 

第一個橫杠-前面必須是頂點集合(冒號后面是別名,別名可以省略)

依據這個范式,最精簡的寫法是:

source = SELECT s FROM source:s -()-> ;

 

舉例說明:

source = SELECT t FROM source:s -(:e)-> :t

上面的寫法無法寫成(因為dest是頂點集合,不是頂點類型):

dest = SELECT t FROM :s -(:e)-> dest:t

tiger和arango邊的方向性

arangodb里面的邊都是有向邊,但是遍歷方向是可以指定的,也是支持反向遍歷。

FOR vertext[] IN []

FOR v,e,p in[1..3]

OUTBOUND|INBOUND|ANY startVertex [EDGES]

FILTER ...

 

tiger的GSQL里面要實現arangodb的AQL中的設定方向的效果,最好的方式是創建邊的時候就定下來這條邊是單向邊還雙向邊。如果是單向邊,創建邊的時候就定好了的出的還是進的,即OUTBOUND還是INBOUND的。

如果創建邊的時候指定雙向邊,那么遍歷就是ANY方式。

在tiger的query里面不能再直接指定邊的方向性了。

 

 

另外,如果都是雙向邊,這是遍歷默認相當於arangodb的ANY方向,如何指定方向呢?

 

 

部署

安裝

groupadd graph

useradd graph -g graph

 

visudo(添加如下一行)

graph  ALL=(ALL) NOPASSWD:ALL

 

su - graph

wget http://dl.tigergraph.com/developer-edition/tigergraph-2.2.4-developer-patch.tar.gz

tar -zxvf tigergraph-2.2.4-developer-patch.tar.gz

cd tigergraph-2.2.4-developer

sudo ./install.sh (填入系統賬號,比如當前使用graph用戶,再填入安裝路徑即可)

 

卸載

官方沒有提供卸載方式

 

建議先停掉tiger:

gadmin stop

 

然后注釋掉crontab任務。

 

然后root用戶下重新執行:

./install.sh -u tiger -p tiger -r /home/tiger/

 

./install.sh -l 40dd21b0acef8f25eca40f6a3077d458db09ea5925ba7da56894d4dcd8928d9c9340876800

gadmin --set license.key 40dd21b0acef8f25eca40f6a3077d458db09ea5925ba7da56894d4dcd8928d9c9340876800

 

啟動和關閉

關閉tigergraph:

gadmin stop

 

 

啟動tigergraph:

gadmin start

數據接入

rest導入(post)

http://192.168.1.234:9000/graph/work_graph

{

    "vertices": {

        "person": {

            "id11": {

                "id": {

                    "value": "sssssssss"

                },

                "gender": {

                    "value": "ttttttttttt"

                }

            }

        }

    }

}

 

gsql本地導入

USE GRAPH socialNet // v1.2

CREATE VERTEX engineer(PRIMARY_ID engineerId STRING, id STRING, locationId STRING, skillSet SET<INT>, skillList LIST<INT>, interestSet SET<STRING COMPRESS>, interestList LIST<STRING COMPRESS>)

CREATE VERTEX company(PRIMARY_ID clientId STRING, id STRING, country STRING)

CREATE UNDIRECTED EDGE worksFor(FROM engineer, TO company, startYear INT, startMonth INT, fullTime BOOL)

 

CREATE LOADING JOB loadMember FOR GRAPH socialNet {

  DEFINE FILENAME f;

  LOAD f

    TO VERTEX engineer VALUES($0, $0, $1, _, _, SPLIT($3,"|"), SPLIT($3,"|") ),

    TO TEMP_TABLE t2(id, skill) VALUES ($0, flatten($2,"|",1));

 

  LOAD TEMP_TABLE t2

    TO VERTEX engineer VALUES($0, _, _, $"skill", $"skill", _, _);

}

 

CREATE LOADING JOB loadCompany FOR GRAPH socialNet {

  DEFINE FILENAME f;

  LOAD f TO VERTEX company VALUES($0, $0, $1);

}

 

CREATE LOADING JOB loadMemberCompany FOR GRAPH socialNet {

  DEFINE FILENAME f;

  LOAD f TO EDGE worksFor VALUES($0, $1, $2, $3, $4);

}

 

RUN LOADING JOB loadMember USING f="./engineers"

RUN LOADING JOB loadCompany USING f="./companies"

RUN LOADING JOB loadMemberCompany USING f="./engineer_company"

 

 

數據查詢

shell方式

java -jar /home/graph/tigergraph/tigergraph/dev/gdk/gsql/lib/gsql_client.jar ls

 

rest方式

curl -X POST  \

-H "Authorization: Basic dGlnZXJncmFwaDp0aWdlcmdyYXBo" \

-H "Cookie: {"TERMINAL_WIDTH":"270","CLIENT_PATH":"/home/graph","session":"3458564839407596.1421093678"}" \

-d "LS" \

http://127.0.0.1:8123/gsql/file

 

 

curl -X POST \

-H "Authorization: Basic dGlnZXJncmFwaDp0aWdlcmdyYXBo" \

-H 'Cookie: {"TERMINAL_WIDTH":"270","CLIENT_PATH":"/home/graph","session":"3458564839407596.1421093678"}' \

-d "ls" http://127.0.0.1:8123/gsql/file

 

 

 

數據存儲

數據導入后文件存放路徑:

/home/graph/tigergraph-2.2.4/tigergraph/gstore/0/part/.mv/21/1547711697574/vertex.bin

常用命令

鏈接:

https://docs.tigergraph.com/admin/admin-guide/installation-and-configuration/installation-guide

 

系統管理

查看當前模塊狀態:

gadmin status

 

gsql --version

 

清空數據的三種方法:

 

只是清空數據(只能用於超級用戶):

gsql CLEAR GRAPH STORE -HARD

 

清空數據和表結構(和drop all效果一樣,會停掉resttpp,gse,gpe模塊):

gsql --reset

 

刪除數據和表結構(報告頂點、邊、圖)會停掉resttpp,gse,gpe模塊:

gsql DROP ALL

 

 

關閉tigergraph:

gadmin stop

 

 

啟動tigergraph:

gadmin start

 

查看tiger所有配置:

gadmin --dump-config

 

 

列出tiger所有日志文件路徑:

gadmin log

 

kafka管理

查看tiger的kakfa的主題:

cd /home/tiger/tigergraph/kafka/bin/

./kafka-topics.sh --zookeeper localhost:19999 --describe

Topic:deltaQ_GPE_1Q   PartitionCount:1 ReplicationFactor:1   Configs:

      Topic: deltaQ_GPE_1Q  Partition: 0     Leader: 1  Replicas: 1      Isr: 1

Topic:post_log_Q PartitionCount:1 ReplicationFactor:1   Configs:

      Topic: post_log_Q     Partition: 0     Leader: 1  Replicas: 1      Isr: 1

Topic:post_log_Q_RESTPP_1Q  PartitionCount:1 ReplicationFactor:1   Configs:

      Topic: post_log_Q_RESTPP_1Q Partition: 0     Leader: 1  Replicas: 1      Isr: 1

默認有三個topic(都是1個分區):

deltaQ_GPE_1Q

post_log_Q

post_log_Q_RESTPP_1Q

 

查看tiger的kafka的有哪些消費組:

cd /home/tiger/tigergraph/kafka/bin/

./kafka-consumer-groups.sh --zookeeper localhost:19999 --list

 

查看kafka的topic的偏離值:

cd /home/tiger/tigergraph/kafka/bin/

./kafka-run-class.sh kafka.tools.GetOffsetShell --broker-list localhost:30002 --topic deltaQ_GPE_1Q

 

./kafka-run-class.sh kafka.tools.GetOffsetShell --broker-list localhost:30002 --topic post_log_Q

 

./kafka-run-class.sh kafka.tools.GetOffsetShell --broker-list localhost:30002 --topic post_log_Q_RESTPP_1Q

 

經過多輪數據接入性能測試表明(實際導入的數據是6406889 ,topic的偏離值deltaQ_GPE_1Q:0:6406889):

官方的restpp接口post數據的導入方式,是通過deltaQ_GPE_1Q這個kafka的topic進行緩沖的。

kafka消息格式是字節流

 

消費kafka:

/home/tiger/tigergraph/kafka/bin/kafka-console-consumer.sh \

--bootstrap-server localhost:30002 \

--topic deltaQ_GPE_1Q \

--consumer-property group.id=geektcp

 

如果從頭開始消費,增加如下參數:

//--fromeginning

GSQL

語法

聲明頂點

VERTEX<person> p1;

startpoint = to_vertex("c4", "company");

 

定義元組

(必須在累加器前面定義,參考C++的語法規則):

TYPEDEF TUPLE <VERTEX v, EDGE e> CHILD;

 

聲明累加器

OrAccum @@found  = false;

OrAccum @notSeen = true;

ListAccum<VERTEX> @childsVetex;

ListAccum<EDGE> @childsEdges;

 

 

賦值頂點

(和聲明分開):

startpoint = to_vertex("c4", "company");

 

filter關鍵字

跟arangodb的filter不同,這不是一個通用過濾器,只能在伴隨neighbors和neighborAttribute這兩個函數時過濾,而且只能在ACCUM語句塊中使用:

s.neighbors().filter(true),

v.@diffCountry += v.neighborAttribute("worksFor", "company", "id")

.filter(v.locationId != company.country),

 

 

JSONARRAY轉LIST

JSONARRAY arr;

arr = filterObject.getJsonArray("filterEdgeType");

j = 0;

WHILE(j<arr.size()) DO

@@list += arr.getString(j);

j+=1;

END;

 

ACCUM關鍵字

用於一階累加

 

POST-ACCUM關鍵字

用於二階累加

 

一個語法糖(官方文檔沒有明確解釋,但有這個用法,見《運算符、函數和表達式->表達式聲明》):

二階累加要調用一階累加的變量時,加單引號即可。例如

  V = SELECT s

            FROM Start:s -(:e)-> :t

            ACCUM t.@received_score += s.@score/(s.outdegree() +1),

                     t.@test += 2,

                     test1 = s.@score

            POST-ACCUM// s.@score = (1.0-damping) + damping * s.@received_score,

                s.@received_score = 0,

                   s.@score = 11,

                @@maxDiff += abs(s.@score - s.@score'),

                   test2 = s.@score',

                   test3 = s.@score;

 

POST-ACCUM 里面的s.@score' 其實就是 ACCUM的變量s.@score

 

語法約束匯總

  • 1、PRINT語句不能打印局部累加器;

 

  • 2、僅當我們只選擇了頂點集變量或頂點表達式集合中的某一部分的時候,PRINT才會打印出頂點的詳細信息。 而當打印單個頂點時(即從一個變量或累加器獲得數據,且它的數據類型是VERTEX),只打印頂點id。

 

  • 3、局部變量只能在ACCUM,POST-ACCUM或UPDATE SET子句中聲明,並且其作用域也僅限於該子句。 局部變量只能是基本類(例如INT,FLOAT,DOUBLE,BOOL,STRING,VERTEX),且必須在同一語句中聲明的同時初始化局部變量

 

  • 4、在局部變量的作用域內,同一級的子句中不能聲明另一個相同名稱的局部變量。 但是,一個新的與該變量同名的變量可以在低級別子句中(例如又嵌套了一層SELECT或UPDATE語句)使用。 即低級別的聲明只在該級別工作。

 

  • 5、聲明頂點集變量時,可以選擇將一組頂點類型指定給頂點集變量。 如果未明確指定頂點集變量的類型,則系統通過頂點集值隱含的類型來輸出。 選擇的類型可以是ANY(表示所有類型),下划線“_” (等效於ANY)或任何被明確說明的頂點類型。

 

 

  • 6、在頂點集變量聲明中,類型說明符跟在變量名后面,並且應該用括號括起來,如:vSetName(type)

 

 

  • Ø7、通常賦值語句可以放在變量聲明后的任何地方。然而,它仍然有兩個限制。該限制適用於“內層”語句,即被包含在一個上層的語句塊中的語句。

 

SELECT或UPDATE語句的正文內不允許使用全局累加器賦值

在ACCUM或POST-ACCUM子句中允許對全局變量賦值,但只有退出該子句后該值才生效。 因此,如果同一全局變量有多個賦值語句,則只有最后一個賦值語句才會生效。

ACCUM子句中不允許使用頂點屬性賦值。 但是,允許對邊屬性賦值。 這是因為ACCUM子句是由邊的集合迭代而來。

 

使用通用的VERTEX作為元素類型的任何累加器都不能由LOADACCUM()初始化。

 

 

  • 8、每個查詢都被視為一個事務(transaction)。 因此,在整個查詢操作完成(確認完成)之前,對於圖數據的修改不會生效。因此,某個查詢中的數據更改操作不會影響同一查詢中的任何其他語句。

 

 

 

  • 10、在ACCUM子句中不允許更新頂點的屬性值,因為這樣的更新動作是並行運行的,同一個值可能會多次更新,從而導致輸出的結果不確定。 如果頂點屬性值的更新取決於邊的屬性值,請使用附屬於頂點的累加器來保存對應的值,然后在POST-ACCUM子句中更新頂點的屬性值。

 

  • 11、元組必須在查詢中的任何其他語句之前被首先定義。

 

  • 12、申明一個頂點變量不要復制,單獨一行再賦值。

 

  • 13、evaluate傳遞的表達式字符串不能包含逗號。

影響是:tiger支持基礎條件的復雜組合過濾條件。不過這些復雜條件要寫死在存儲過程里面。

 

 

  • 14、tiger的邏輯運算符NOT里面不能使用頂點或者邊的type字段,只能使用屬性,其他運算符沒有限制。

官方:NOT運算符不能與.type屬性選擇器結合使用。 要檢查邊或頂點類型是否不等於給定類型,請使用!=運算符

 

  • 15、累加器的關鍵字都是區分大小寫的,比如SetAccum不能寫成SETACCUM

 

  • 16、to_vertex_set允許對應的頂點不存在,to_vertex則會導致存儲過程執行失敗,查不出數據。

 

  • 17、本地導入數據的語句CREATE LOADING JOB里面,加載邊時,邊表的表結構中的起點和終點,必須是確定,不能通配符*,如果創建邊表使用了通配符*,那么無法用CREATE LOADING JOB方式導入數據。

 

開發

tiger的select語句其實本質上用C++語言,通過多線程,廣度優先方式進行遍歷。

這就是為什么全路徑查詢時,如果有多條路徑時,結果集存在逆序。

 

算法

K層展開

CREATE QUERY expand_filter_pro3 (String filterStr) FOR GRAPH work_graph {

    JSONOBJECT filter_object,filter_origin, filter_tmp;

    INT filter_depth, filter_nodeSize, filter_sum, i, j;

    BOOL filter_direction, filter_enable;

    JSONARRAY filter_edges,filter_nodes,filter_origins, filter_collections,filter_value;

      STRING filter_expression, filter_key;

    MinAccum<INT> @accum_dis;

    OrAccum @accum_visited;

    ListAccum<VERTEX> @accum_path;

    ListAccum<STRING> @accum_type;

 

    OrAccum @@accum_on;

    SetAccum<STRING> @@accum_edges;

    SetAccum<STRING> @@accum_nodes;

    ListAccum<VERTEX> @@accum_origins;

    SetAccum<EDGE> @@accum_edges_result;

    MapAccum<STRING, ListAccum<STRING>> @@filter_map;

    ListAccum<STRING> @@filter_value;

     

    filter_object = parse_json_object(filterStr);

    filter_origins = filter_object.getJsonArray("origins");

    filter_nodes = filter_object.getJsonArray("nodes");

    filter_edges = filter_object.getJsonArray("edges");

    filter_direction = filter_object.getBool("direction");

    filter_enable = filter_object.getBool("enable");

    filter_depth = filter_object.getInt("depth");

    filter_nodeSize = filter_object.getInt("nodeSize");

    filter_sum = filter_object.getInt("sum");

    filter_expression = filter_object.getString("expression");

    filter_collections = filter_object.getJsonArray("collection");

   

    j = 0;

    WHILE(j < filter_origins.size()) DO

        filter_origin = filter_origins.getJsonObject(j);

        @@accum_origins += to_vertex(filter_origin.getString("id"), filter_origin.getString("type"));

        j += 1;

    END;

    j = 0;

    WHILE(j < filter_edges.size()) DO

        @@accum_edges += filter_edges.getString(j);

        j += 1;

    END;

    j = 0;

    WHILE(j < filter_nodes.size()) DO

        @@accum_nodes += filter_nodes.getString(j);

        j += 1;

    END;

      j = 0;

    WHILE(j < filter_collections.size()) DO

          filter_tmp = filter_collections.getJsonObject(j);

          filter_key = filter_tmp.getString("key");

          filter_value = filter_tmp.getJsonarray("value");

          PRINT filter_value;

          i=0;

          WHILE(i < filter_value.size()) DO

              @@filter_value += filter_value.getString(i);

              PRINT @@filter_value;

              i+=1;

          END;

          @@filter_map += (filter_key -> @@filter_value);

          j += 1;

    END;

      PRINT @@filter_map;

      //PRINT @@filter_map.get("company");

   

    source = { @@accum_origins };

    result = { @@accum_origins };

    IF(filter_enable) THEN

        source = SELECT s

            FROM source:s - (:e) -> :t

            ACCUM s.@accum_visited += true,

                 s.@accum_dis = 0,

                 s.@accum_path = s;

        WHILE( source.size()>0 AND result.size() < filter_nodeSize) LIMIT filter_depth DO

            source = SELECT t

                FROM source:s -(:e)-> :t

                WHERE t.@accum_visited == false

                    AND @@accum_edges.contains(e.type)

                    AND @@accum_nodes.contains(t.id)

                    AND s.@accum_dis < filter_sum

                      //AND t.city != "dongguan" OR NOT( @@filter_map.get("company").contains(t.city) AND t.sex == "female")

                      AND evaluate(filter_expression)

                ACCUM t.@accum_dis += s.@accum_dis + 1,

                    t.@accum_path = s.@accum_path + [t],

                    t.@accum_visited += true,

                    @@accum_on += s.quadrant > 4,

                    @@accum_edges_result += e;

               //HAVING t.city != "dongguan"

                   //   OR ( t.city == "dongguan" AND t.sex == "female");

            result = result UNION source;

        END;

        PRINT result as vertices;

        PRINT @@accum_edges_result AS edges;

    END;

}

 

最短路徑

CREATE QUERY shortest_path(VERTEX startpoint, VERTEX endpoint, INT depth = 5) FOR GRAPH work_graph {

    OrAccum @@found  = false;

    OrAccum @notSeen = true;

    ListAccum<VERTEX> @childsVetex;

    ListAccum<EDGE> @childsEdges;

    ListAccum<VERTEX> @@vertexes;

    ListAccum<EDGE> @@edges;

    MapAccum<VERTEX, ListAccum<VERTEX>> @@mapVertex;

    MapAccum<VERTEX, ListAccum<EDGE>> @@mapEdge;

 

    ListAccum<VERTEX> @@tmppoint;

    ListAccum<VERTEX> @@tmpkeys;

    String msg;

 

    Start  = { startpoint };

 

    result = SELECT v

        FROM Start:v

        ACCUM v.@notSeen = false;

 

    WHILE NOT @@found LIMIT depth DO

        Start = SELECT t

            FROM Start:s - (:e) -> :t

                WHERE t.@notSeen

                ACCUM t.@notSeen = false,

                      t.@childsVetex += s,

                      t.@childsEdges += e,

                      if t == endpoint THEN

                            @@found += true

                      END

                  POST-ACCUM

                      @@mapVertex += (t -> t.@childsVetex),

                      @@mapEdge += (t -> t.@childsEdges);

    END;

 

    @@tmppoint += endpoint;

    @@vertexes += endpoint;

    WHILE true LIMIT 10 DO

        @@tmpkeys.clear();

        FOREACH key in @@tmppoint DO

            IF(@@mapVertex.containsKey(key)) THEN

                @@tmpkeys += @@mapVertex.get(key);

                @@vertexes += @@mapVertex.get(key);

                @@edges += @@mapEdge.get(key);

            END;

        END;

 

        @@tmppoint = @@tmpkeys;

 

        IF(@@mapVertex.containsKey(startpoint)) THEN

            BREAK;

        END;

    END;

 

    IF @@found THEN

        PRINT @@edges;

        PRINT @@vertexes;

    ELSE

          msg = "Can't find shortest path within max depth";

        PRINT msg ;

          PRINT depth;

    END;

}

 

全路徑

CREATE QUERY full_path() FOR GRAPH work_graph {

    VERTEX startpoint;

    VERTEX endpoint;

    INT graph_depth, result_depth;

 

    OrAccum @@found_start  = FALSE;

    OrAccum @@found_end  = FALSE;

    AndAccum @@found  = TRUE;

 

    OrAccum @notSeen = TRUE;

 

    SetAccum<VERTEX> @nextVetexes;

    SetAccum<EDGE> @nextEdges;

 

    SetAccum<VERTEX> @lastVetexes;

    SetAccum<EDGE> @lastEdges;

 

    SetAccum<VERTEX> @@vertexes;

    SetAccum<EDGE> @@edges;

 

    MapAccum<VERTEX, SetAccum<VERTEX>> @@mapVertex;

    MapAccum<VERTEX, SetAccum<EDGE>> @@mapEdge;

 

    MapAccum<VERTEX, SetAccum<VERTEX>> @@mapVertexReverse;

    MapAccum<VERTEX, SetAccum<EDGE>> @@mapEdgeReverse;

 

    SetAccum<VERTEX> @@tmppoint;

    SetAccum<VERTEX> @@tmpkeys;

 

    SetAccum<VERTEX> @@startlist;

    SetAccum<VERTEX> @@endlist;

 

    graph_depth = 6;

    result_depth = graph_depth * 2;

    startpoint = to_vertex("p7", "persons");

    endpoint = to_vertex("s4", "skill");

    @@startlist += startpoint;

    @@endlist += endpoint;

    Start (ANY) = {@@startlist};

   

    result = SELECT v

        FROM Start:v

        ACCUM v.@notSeen = FALSE;

 

    WHILE TRUE LIMIT graph_depth DO

        Start = SELECT t

            FROM Start:s - (:e) -> :t

                WHERE t.@notSeen // and e.type !="all_to_skill"

                ACCUM t.@notSeen = FALSE,

                      t.@lastVetexes += s,

                      t.@lastEdges += e,

                      s.@nextVetexes += t,

                      s.@nextEdges += e

                  POST-ACCUM

                      @@mapVertex += (t -> t.@lastVetexes),

                      @@mapEdge += (t -> t.@lastEdges),

                      @@mapVertexReverse += (s -> s.@nextVetexes),

                      @@mapEdgeReverse += (s -> s.@nextEdges);

    END;

 

    @@tmppoint += endpoint;

    @@vertexes += endpoint;

    WHILE TRUE LIMIT result_depth DO

        @@tmpkeys.clear();

        FOREACH key in @@tmppoint DO

            IF(@@mapVertex.containsKey(key)) THEN

                @@tmpkeys += @@mapVertex.get(key);

                @@vertexes += @@mapVertex.get(key);

                @@edges += @@mapEdge.get(key);

                  END;

            IF(@@mapVertexReverse.containsKey(key)) THEN

                @@tmpkeys += @@mapVertexReverse.get(key);

                @@vertexes += @@mapVertexReverse.get(key);

                @@edges += @@mapEdgeReverse.get(key);

            END;

        END;

        @@tmppoint = @@tmpkeys;

    END;

 

    FOREACH point in @@startlist DO

        IF(@@vertexes.contains(point)) THEN

            @@found_start += TRUE;

        END;

    END;

    FOREACH point in @@endlist DO

        IF(@@vertexes.contains(point)) THEN

            @@found_end += TRUE;

        END;

    END;

 

    @@found += @@found_start;

    @@found += @@found_end;

    PRINT @@found;

    PRINT @@edges;

    PRINT @@vertexes;

}

社區發現

louvain算法

pagerank

標簽傳播

高級過濾

余弦相似

 

循環三角

 

其他算法

 

高級過濾

高級過濾條件只能在結果集里面進行

因為高級過濾條件里面包含不只一個條件,如果只是查出一部分結果就進行過濾,那么這個filter要執行多次,這其實是低效的。每次查出一部分結果,比如多層展開,遍歷第一層就解析過濾條件然后過濾一次,第二層又來一遍,效率很低。

傳統關系型數據庫的過濾條件where語句不是結果集里過濾的,而是查詢過程中過濾。相當於圖查詢的每層展開過濾。

傳統關系型數據庫的復雜嵌套sql是從結果集里面過濾的,相當於圖查詢的結果集過濾。

 

 

 

常見問題

問題1:tiger的字符串轉json報錯

tiger的存儲過程中解析json,不能直接一步到位,想這樣是語法是對的,但無法正常編譯:

JSONOBJECT json;

json = parse_json_object( jsonStr );

param = json.getJsonObject("param");

PRINT param.getJsonObject("options").getString("edges");

 

正確的寫法:

JSONOBJECT options;

options = json.getJsonObject("options");

PRINT options.getString("direction");

 

問題2:tiger的sql里面引入文件,當tiger使用集群模式時,文件是放在哪個節點還是每個節點都要有?

這要看是否啟用HA,如果沒有,那么文件鎖每個節點都存放對應分片。

如果有HA,假定副本是兩個,那么每個分片會在兩個節點存放。

 

 

 

開發包和企業版差別

tiger分為兩個版本:Developer Edition 和 Enterprise Edition

開發版只支持單點模式,並且不支持版本升級;

企業版支持單點和集群模式

 

序號

功能

開發版

企業版

1

 集群

 否

 是

2

 多圖

 否

 是

3

 修改圖

 否

 是

4

 節點數無限

 否

 根據license

5

 高可用

 否

 是

6

 權限認證

 否

 是

7

 數據備份

 否

 是

8

 

 

 

9

 

 

 

10

 

 

 

11

 

 

 

12

 

 

 

13

 

 

 

14

 

 

 

15

 

 

 

16

 

 

 

17

 

 

 

18

 

 

 

19

 

 

 

20

 

 

 

參考文檔

下載地址:

http://dl.tigergraph.com/developer-edition/tigergraph-2.2.4-developer-patch.tar.gz

 

官方文檔:

https://docs.tigergraph.com/

 

 

官方開發文檔:

https://www.tigergraph.com/developers/?utm_campaign=2018%20Developer%20Edition&utm_source=hs_automation&utm_medium=email&utm_content=63627934&_hsenc=p2ANqtz-9WiQx4ts5owPLxV7gy_d4JLvaLUTpa3axLLBObsV6c00DSzrw_gV9txh6Gr1af1RBpIeqBag9VWrvl2rxHlTTAHWTdLA&_hsmi=63627934

 

 

GQL:

https://doc.tigergraph.com/GSQL-101.html?utm_campaign=2018%20Developer%20Edition&utm_source=hs_automation&utm_medium=email&utm_content=63627934&_hsenc=p2ANqtz-9WiQx4ts5owPLxV7gy_d4JLvaLUTpa3axLLBObsV6c00DSzrw_gV9txh6Gr1af1RBpIeqBag9VWrvl2rxHlTTAHWTdLA&_hsmi=63627934

 

 

用戶手冊:

https://doc.tigergraph.com/TigerGraph-Platform-Knowledge-Base-and-FAQs.html?utm_campaign=2018%20Developer%20Edition&utm_source=hs_automation&utm_medium=email&utm_content=63627934&_hsenc=p2ANqtz-9WiQx4ts5owPLxV7gy_d4JLvaLUTpa3axLLBObsV6c00DSzrw_gV9txh6Gr1af1RBpIeqBag9VWrvl2rxHlTTAHWTdLA&_hsmi=63627934

 

 

web使用手冊:

https://doc.tigergraph.com/TigerGraph-Platform-Overview.html?utm_campaign=2018%20Developer%20Edition&utm_source=hs_automation&utm_medium=email&utm_content=63627934&_hsenc=p2ANqtz-9WiQx4ts5owPLxV7gy_d4JLvaLUTpa3axLLBObsV6c00DSzrw_gV9txh6Gr1af1RBpIeqBag9VWrvl2rxHlTTAHWTdLA&_hsmi=63627934

 

 

tigergraph基礎架構:

https://doc.tigergraph.com/TigerGraph-Platform-Overview.html?utm_campaign=2018%20Developer%20Edition&utm_source=hs_automation&utm_medium=email&utm_content=63627934&_hsenc=p2ANqtz-9WiQx4ts5owPLxV7gy_d4JLvaLUTpa3axLLBObsV6c00DSzrw_gV9txh6Gr1af1RBpIeqBag9VWrvl2rxHlTTAHWTdLA&_hsmi=63627934

 

 

rest api:

https://docs.tigergraph.com/dev/restpp-api/restpp-requests

 

構建測試數據:

https://docs.tigergraph.com/dev/gsql-ref/querying/appendix/example-graphs#socialnet

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM