ไป‹็ปๆ–ฐ้กน็›ฎ๏ผ ng_ai๏ผšNebulaGraph ็š„ๅ›พ็ฎ—ๆณ•ๅฅ—ไปถ๏ผŒๅฅฝ็”จ็š„ NebulaGraph ็š„ high-level Python Algorithm API๏ผŒๅฎƒ็š„็›ฎๆ ‡ๆ˜ฏ่ฎฉ NebulaGraph ็š„ๆ•ฐๆฎ็ง‘ๅญฆๅฎถ็”จๆˆท่ƒฝๅคŸ็”จๅพˆๅฐ‘็š„ไปฃ็ ้‡ๆ‰ง่กŒๅ›พไธŠ็š„็ฎ—ๆณ•็›ธๅ…ณ็š„ไปปๅŠกใ€‚

่ฟ™ๅ‘จ๏ผŒNebulaGraph 3.5.0 ๅ‘ๅธƒๅ•ฆ๏ผŒ@whitewum ๅด่€ๅธˆๅปบ่ฎฎๆˆ‘ไปฌๆŠŠ่€Œไน‹ๅ‰ไธ€ๆฎตๆ—ถ้—ด NebulaGraph ็คพๅŒบ้‡Œๅผ€ๅฏ็š„ๆ–ฐ้กน็›ฎ ng_ai ๅ…ฌๅผ€็ป™ๅคงๅฎถ๏ผŒๆœฌๆ–‡ๅฐฑๆ˜ฏ็ฌฌไธ€็ฏ‡ไป‹็ป ng_ai ็š„ๆ–‡็ซ ๏ผ

ng_ai ็š„ๅ…จๅๆ˜ฏ๏ผšNebulagraph AI Suite๏ผŒ้กพๅๆ€ไน‰๏ผŒๅฎƒๆ˜ฏๅœจ NebulaGraph ไน‹ไธŠ่ท‘็ฎ—ๆณ•็š„ Python ๅฅ—ไปถ๏ผŒๅธŒๆœ›่ƒฝ็ป™ NebulaGraph ็š„ๆ•ฐๆฎ็ง‘ๅญฆๅฎถ็”จๆˆทไธ€ไธช่‡ช็„ถใ€็ฎ€ๆด็š„้ซ˜็บง API๏ผŒ็”จๅพˆๅฐ‘็š„ไปฃ็ ้‡ๆ‰ง่กŒๅ›พไธŠ็š„็ฎ—ๆณ•็›ธๅ…ณ็š„ไปปๅŠกใ€‚

ๅœจ ng_ai ่ฟ™ไธชๅผ€ๆบ้กน็›ฎ้‡Œ๏ผŒๆˆ‘ไปฌๅธŒๆœ›ๅฟซ้€Ÿ่ฟญไปฃใ€ๅ…ฌๅผ€่ฎจ่ฎบใ€ๆผ”่ฟ›ๅฎƒ๏ผŒ่€Œ่ฟ™่ƒŒๅŽ็š„็›ฎๆ ‡ๆ˜ฏ๏ผš

Simplifying things in surprising ways.

ไธบไบ†่ฎฉ NebulaGraph ็คพๅŒบ็š„ๅŒๅญฆๆ‹ฅๆœ‰้กบๆป‘็š„็ฎ—ๆณ•ไฝ“้ชŒ๏ผŒng_ai ๆœ‰ไปฅไธ‹็‰น็‚น๏ผš

  • ไธŽ NebulaGraph ็ดงๅฏ†็ป“ๅˆ๏ผŒๆ–นไพฟไปŽๅ…ถไธญ่ฏปใ€ๅ†™ๅ›พๆ•ฐๆฎ
  • ๆ”ฏๆŒๅคšๅผ•ๆ“Žใ€ๅŽ็ซฏ๏ผŒ็›ฎๅ‰ๆ”ฏๆŒ Spark๏ผˆNebulaGraph Algorithm๏ผ‰ใ€NetworkX๏ผŒไน‹ๅŽไผšๆ”ฏๆŒ DGLใ€PyG
  • ๅ‹ๅฅฝใ€็ฌฆๅˆ็›ด่ง‰็š„ API ่ฎพ่ฎก
  • ไธŽ NebulaGraph ็š„ UDF ๆ— ็ผ็ป“ๅˆ๏ผŒๆ”ฏๆŒไปŽ Query ไธญ่ฐƒ็”จ ng_ai ไปปๅŠก
  • ๅ‹ๅฅฝ็š„่‡ชๅฎšไน‰็ฎ—ๆณ•ๆŽฅๅฃ๏ผŒๆ–นไพฟ็”จๆˆท่‡ชๅทฑๅฎž็Žฐ็ฎ—ๆณ•๏ผˆๅฐšๆœชๅฎŒๆˆ๏ผ‰
  • ไธ€้”ฎ่ฏ•็Žฉ็Žฏๅขƒ๏ผˆๅŸบไบŽ Docker Extention๏ผ‰

ๅฆ‚ๆžœๅœจไธ€ไธชๅคงๅ›พไธŠ๏ผŒๅŸบไบŽ Nebula-Algorithms ๅˆ†ๅธƒๅผๅœฐ่ท‘ pagerank ็ฎ—ๆณ•๏ผŒๆˆ‘ไปฌๅฏไปฅ่ฟ™ไนˆๅš๏ผš

python

from ng_ai import NebulaReader

# read data with spark engine, scan mode
reader = NebulaReader(engine="spark")
reader.scan(edge="follow", props="degree")
df = reader.read()

# run pagerank algorithm
pr_result = df.algo.pagerank(reset_prob=0.15, max_iter=10)

ๅ‡่ฎพๆˆ‘ไปฌ่ฆ่ท‘ไธ€ไธช label propagation ็ฎ—ๆณ•๏ผŒ็„ถๅŽๆŠŠ็ป“ๆžœๅ†™ๅ›ž NebulaGraph๏ผŒๆˆ‘ไปฌๅฏไปฅ่ฟ™ไนˆๅš๏ผš

ๅ…ˆ็กฎไฟ่ฆๅ†™ๅ›ž TAG ็š„ schema ๅทฒ็ปๅˆ›ๅปบๅฅฝไบ†๏ผŒๅ†™ๅˆฐ label_propagation.cluster_id ๅญ—ๆฎต้‡Œ๏ผš

sql

CREATE TAG IF NOT EXISTS label_propagation (
    cluster_id string NOT NULL
);

ๆˆ‘ไปฌๅ…ˆๆ‰ง่กŒ็ฎ—ๆณ•๏ผš

python

df_result = df.algo.label_propagation()

ๅ†็œ‹ไธ€ไธ‹็ป“ๆžœ็š„ schema๏ผš

python

df_result.printSchema()

root
 |-- _id: string (nullable = false)
 |-- lpa: string (nullable = false)

็„ถๅŽ๏ผŒไปฃ็ ้‡Œ่ฟ™ไนˆๅ†™๏ผŒๆˆ‘ไปฌๆŠŠ lpa ็š„็ป“ๆžœๅ†™ๅ›ž NebulaGraph ไธญ็š„ cluster_id ๅญ—ๆฎต้‡Œ๏ผˆ{"lpa": "cluster_id"}๏ผ‰๏ผš

python

from ng_ai import NebulaWriter
from ng_ai.config import NebulaGraphConfig

config = NebulaGraphConfig()
writer = NebulaWriter(
    data=df_result, sink="nebulagraph_vertex", config=config, engine="spark"
)

# map column louvain into property cluster_id
properties = {"lpa": "cluster_id"}

writer.set_options(
    tag="label_propagation",
    vid_field="_id",
    properties=properties,
    batch_size=256,
    write_mode="insert",
)
# write back to NebulaGraph
writer.write()

ๆœ€ๅŽ๏ผŒๆˆ‘ไปฌๅฏไปฅ้ชŒ่ฏไธ€ไธ‹็ป“ๆžœๅ•ฆ๏ผš

cypher

USE basketballplayer;
MATCH (v:label_propagation)
RETURN id(v), v.label_propagation.cluster_id LIMIT 3;

็ป“ๆžœ๏ผš

SQL

+-------------+--------------------------------+
| id(v)       | v.label_propagation.cluster_id |
+-------------+--------------------------------+
| "player103" | "player101"                    |
| "player113" | "player129"                    |
| "player121" | "player129"                    |
+-------------+--------------------------------+

ๆ›ด่ฏฆ็ป†็š„ไพ‹ๅญๅ‚่€ƒ๏ผšng_ai/examples

ไปŽ NebulaGraph 3.5.0 ไน‹ๅŽ๏ผŒๆˆ‘ไปฌๅฏไปฅๅ†™่‡ชๅทฑ็š„ UDF ๆฅไปŽ nGQL ้‡Œ่ฐƒ็”จ่‡ชๅทฑๅฎž็Žฐ็š„ๅ‡ฝๆ•ฐ๏ผŒng_ai ไนŸ็”จ่ฟ™ไธช่ƒฝๅŠ›ๆฅๅฎž็Žฐไบ†ไธ€ไธช ng_ai ๅ‡ฝๆ•ฐ๏ผŒๅฎƒๅฏไปฅไปŽ nGQL ้‡Œ่ฐƒ็”จ ng_ai ็š„็ฎ—ๆณ•๏ผŒไพ‹ๅฆ‚๏ผš

sql

-- Prepare the write schema
USE basketballplayer;
CREATE TAG IF NOT EXISTS pagerank(pagerank string);
:sleep 20;
-- Call with ng_ai()
RETURN ng_ai("pagerank", ["follow"], ["degree"], "spark", {space: "basketballplayer", max_iter: 10}, {write_mode: "insert"})

ๆ›ด่ฏฆ็ป†็š„ไพ‹ๅญๅ‚่€ƒ๏ผšng_ai/examples

ๅœจๅ•ๆœบใ€ๆœฌๅœฐ็š„็Žฏๅขƒ้‡Œ๏ผŒng_ai ๆ”ฏๆŒๅŸบไบŽ NetworkX ่ฟ่กŒ็ฎ—ๆณ•๏ผŒไพ‹ๅฆ‚๏ผš

่ฏปๅ–ๅ›พไธบ ng_ai graph ๅฏน่ฑก๏ผš

python

from ng_ai import NebulaReader
from ng_ai.config import NebulaGraphConfig

# read data with nebula/networkx engine, query mode
config_dict = {
    "graphd_hosts": "graphd:9669",
    "user": "root",
    "password": "nebula",
    "space": "basketballplayer",
}
config = NebulaGraphConfig(**config_dict)
reader = NebulaReader(engine="nebula", config=config)
reader.query(edges=["follow", "serve"], props=[["degree"], []])
g = reader.read()

ๆŸฅ็œ‹ใ€็”ปๅ›พ๏ผš

python

g.show(10)
g.draw()

่ฟ่กŒ็ฎ—ๆณ•๏ผš

python

pr_result = g.algo.pagerank(reset_prob=0.15, max_iter=10)

ๅ†™ๅ›ž NebulaGraph๏ผš

python

from ng_ai import NebulaWriter

writer = NebulaWriter(
    data=pr_result,
    sink="nebulagraph_vertex",
    config=config,
    engine="nebula",
)

# properties to write
properties = ["pagerank"]

writer.set_options(
    tag="pagerank",
    properties=properties,
    batch_size=256,
    write_mode="insert",
)
# write back to NebulaGraph
writer.write()

ๅ…ถไป–็ฎ—ๆณ•๏ผš

python

# get all algorithms
g.algo.get_all_algo()

# get help of each algo
help(g.algo.node2vec)

# call the algo
g.algo.node2vec()

ๆ›ด่ฏฆ็ป†็š„ไพ‹ๅญๅ‚่€ƒ๏ผšng_ai/examples

ๅ†ๆผ”็คบไธ€ไธช NetworkX ๅผ•ๆ“Žๆƒ…ๅ†ตไธ‹๏ผŒ่ฎก็ฎ— Louvainใ€PageRank ๅนถๅฏ่ง†ๅŒ–็š„ไพ‹ๅญ๏ผš

ๅ…ˆๆ‰ง่กŒไธคไธช็ฎ—ๆณ•๏ผš

python

pr_result = g.algo.pagerank(reset_prob=0.15, max_iter=10)
louvain_result = g.algo.louvain()

่ฟ™ๆฌกๆˆ‘ไปฌๆ‰‹ๅ†™ไธ€ไธชๅฅฝ็œ‹ไธ€็‚น็š„็”ปๅ›พๅ‡ฝๆ•ฐ๏ผš

python

from matplotlib.colors import ListedColormap


def draw_graph_louvain_pr(G, pr_result, louvain_result, colors=["#1984c5", "#22a7f0", "#63bff0", "#a7d5ed", "#e2e2e2", "#e1a692", "#de6e56", "#e14b31", "#c23728"]):
    # Define positions for the nodes
    pos = nx.spring_layout(G)

    # Create a figure and set the axis limits
    fig, ax = plt.subplots(figsize=(35, 15))
    ax.set_xlim(-1, 1)
    ax.set_ylim(-1, 1)

    # Create a colormap from the colors list
    cmap = ListedColormap(colors)

    # Draw the nodes and edges of the graph
    node_colors = [louvain_result[node] for node in G.nodes()]
    node_sizes = [70000 * pr_result[node] for node in G.nodes()]
    nx.draw_networkx_nodes(G, pos=pos, ax=ax, node_color=node_colors, node_size=node_sizes, cmap=cmap, vmin=0, vmax=max(louvain_result.values()))

    nx.draw_networkx_edges(G, pos=pos, ax=ax, edge_color='gray', width=1, connectionstyle='arc3, rad=0.2', arrowstyle='-|>', arrows=True)

    # Extract edge labels as a dictionary
    edge_labels = nx.get_edge_attributes(G, 'label')

    # Add edge labels to the graph
    for edge, label in edge_labels.items():
        ax.text((pos[edge[0]][0] + pos[edge[1]][0])/2,
                (pos[edge[0]][1] + pos[edge[1]][1])/2,
                label, fontsize=12, color='black', ha='center', va='center')

    # Add node labels to the graph
    node_labels = {n: G.nodes[n]['label'] if 'label' in G.nodes[n] else n for n in G.nodes()}
    nx.draw_networkx_labels(G, pos=pos, ax=ax, labels=node_labels, font_size=12, font_color='black')

    # Add colorbar for community colors
    sm = plt.cm.ScalarMappable(cmap=cmap, norm=plt.Normalize(vmin=0, vmax=max(louvain_result.values())))
    sm.set_array([])
    cbar = plt.colorbar(sm, ax=ax, ticks=range(max(louvain_result.values()) + 1), shrink=0.5)
    cbar.ax.set_yticklabels([f'Community {i}' for i in range(max(louvain_result.values()) + 1)])

    # Show the figure
    plt.show()


draw_graph_louvain_pr(G, pr_result=pr_result, louvain_result=louvain_result)

ๆ•ˆๆžœๅฆ‚ๅ›พ๏ผš

draw_graph_louvain_pr

ๆ›ด่ฏฆ็ป†็š„ไพ‹ๅญๅ‚่€ƒ๏ผšng_ai/examples

็ป“ๅˆ NebulaGraph ็š„ Jupyter Notebook ๆ’ไปถ: https://github.com/wey-gu/ipython-ngql ๏ผŒๆˆ‘ไปฌ่ฟ˜ๅฏไปฅๆ›ดๆ–นไพฟ็š„ๆ“ไฝœ NebulaGraph๏ผš

ๅœจ Jupyter Notbook ้‡Œๅฎ‰่ฃ…่ฟ™ไธชๆ’ไปถๅฏไปฅ้€š่ฟ‡ ng_ai ็š„ extras ๅฎ‰่ฃ…๏ผš

python

%pip install ng_ai[jupyter]
%load_ext ngql

ไนŸๅฏไปฅๅ•็‹ฌๅฎ‰่ฃ…

python

%pip install ipython-ngql
%load_ext ngql

ไน‹ๅŽ๏ผŒๆˆ‘ไปฌๅฐฑๅฏไปฅๅœจ Notebook ้‡Œ็›ดๆŽฅไฝฟ็”จ %ngql ๅ‘ฝไปคๆฅๆ‰ง่กŒ NGQL ่ฏญๅฅไบ†๏ผš

python

%ngql --address 127.0.0.1 --port 9669 --user root --password nebula
%ngql USE basketballplayer;
%ngql MATCH (v:player{name:"Tim Duncan"})-->(v2:player) RETURN v2.player.name AS Name;

ๆณจ๏ผŒๅคš่กŒ็š„ Query ็”จไธคไธช็™พๅˆ†ๅทๅฐฑๅฅฝไบ† %%ngql

ๆœ€ๅŽ๏ผŒๆˆ‘ไปฌ่ฟ˜่ƒฝๅœจ Jupyter Notebook ้‡Œ็›ดๆŽฅๅฏ่ง†ๅŒ–ๆธฒๆŸ“็ป“ๆžœ๏ผๅช้œ€่ฆ %ng_draw ๅฐฑๅฏไปฅๅ•ฆ๏ผ

python

%ngql match p=(:player)-[]->() return p LIMIT 5
%ng_draw

ๆ•ˆๆžœๅฆ‚ไธ‹๏ผš

ipython-ngql

็Žฐๅœจ ng_ai ่ฟ˜ๅœจๅผ€ๅ‘ไธญ๏ผŒๆˆ‘ไปฌ่ฟ˜ๆœ‰ๅพˆๅคšๅทฅไฝœ่ฆๅš๏ผš

  • ๅฎŒๅ–„ reader ๆจกๅผ๏ผŒ็Žฐๅœจ NebulaGraph/NetworkX ็š„่ฏปๅ–ๆ•ฐๆฎๅชๆ”ฏๆŒ Query-Mode๏ผŒ่ฟ˜้œ€่ฆๆ”ฏๆŒ Scan-Mode
  • ๅฎž็ŽฐๅŸบไบŽ dgl(GNN) ็š„้“พ่ทฏ้ข„ๆต‹ใ€่Š‚็‚นๅˆ†็ฑป็ญ‰็ฎ—ๆณ•๏ผŒไพ‹ๅฆ‚๏ผš

python

model = g.algo.gnn_link_prediction()
result = model.train()
# query src, dst to be predicted

model.predict(src_vertex, dst_vertices)
  • UDA๏ผŒ่‡ชๅฎšไน‰็ฎ—ๆณ•
  • ๅฟซ้€Ÿ้ƒจ็ฝฒๅทฅๅ…ท

ng_ai ๆ˜ฏๅฎŒๅ…จ build in public ็š„๏ผŒๆฌข่ฟŽ็คพๅŒบ็š„ๅคงๅฎถไปฌๆฅๅ‚ไธŽ๏ผŒไธ€่ตทๆฅๅฎŒๅ–„ ng_ai๏ผŒ่ฎฉ NebulaGraph ไธŠ็š„ AI ็ฎ—ๆณ•ๆ›ดๅŠ ็ฎ€ๅ•ๆ˜“็”จ๏ผ

ๆˆ‘ไปฌๅทฒ็ปๅ‡†ๅค‡ๅฅฝไบ†ไธ€้”ฎ้ƒจ็ฝฒ็š„ NebulaGraph + Studio + ng_ai in Jupyter ็š„็Žฏๅขƒ๏ผŒๅช้œ€่ฆๅคงๅฎถไปŽ Docker Desktop ็š„ Extension๏ผˆๆ‰ฉๅฑ•๏ผ‰ไธญๆœ็ดข NebulaGraph๏ผŒๅฐฑๅฏไปฅ่ฏ•ๅฎŒไบ†ใ€‚

ๅœจ Docker Desktop ็š„ๆ’ไปถๅธ‚ๅœบๆœ็ดข NebulaGraph๏ผŒ็‚นๅ‡ปๅฎ‰่ฃ…

  • ๅฎ‰่ฃ… ng_ai playground

่ฟ›ๅ…ฅ NebulaGraph ๆ’ไปถ๏ผŒ็‚นๅ‡ปInstall NX Mode๏ผŒๅฎ‰่ฃ… ng_ai ็š„ NetworkX playground๏ผŒ้€šๅธธ่ฆ็ญ‰ๅ‡ ๅˆ†้’Ÿ็ญ‰ๅพ…ๅฎ‰่ฃ…ๅฎŒๆˆใ€‚

  • ่ฟ›ๅ…ฅ NetworkX playground

็‚นๅ‡ปJupyter NB NetworkX๏ผŒ่ฟ›ๅ…ฅ NetworkX playgroundใ€‚

ng_ai ็š„ๆžถๆž„ๅฆ‚ไธ‹๏ผŒๅฎƒ็š„ๆ ธๅฟƒๆจกๅ—ๆœ‰๏ผš

  • Reader๏ผš่ดŸ่ดฃไปŽ NebulaGraph ่ฏปๅ–ๆ•ฐๆฎ
  • Writer๏ผš่ดŸ่ดฃๅฐ†ๆ•ฐๆฎๅ†™ๅ…ฅ NebulaGraph
  • *Engine๏ผš่ดŸ่ดฃ้€‚้…ไธๅŒ่ฟ่กŒๆ—ถ๏ผŒไพ‹ๅฆ‚ Sparkใ€DGLใ€NetowrkX ็ญ‰
  • Algo๏ผš็ฎ—ๆณ•ๆจกๅ—๏ผŒไพ‹ๅฆ‚ PageRankใ€Louvainใ€GNN_Link_Predict ็ญ‰

ๆญคๅค–๏ผŒไธบไบ†ๆ”ฏๆŒ nGQL ไธญ็š„่ฐƒ็”จ๏ผŒ่ฟ˜ๆœ‰ไธคไธชๆจกๅ—๏ผš

  • ng_ai-udf๏ผš่ดŸ่ดฃๅฐ† UDF ๆณจๅ†Œๅˆฐ NebulaGraph๏ผŒๆŽฅๅ— ng_ai ็š„ query ่ฐƒ็”จ๏ผŒ่ฎฟ้—ฎ ng_ai API
  • ng_ai-api๏ผšng_ai ็š„ API ๆœๅŠก๏ผŒๆŽฅๅ— UDF ็š„่ฐƒ็”จ๏ผŒ่ฎฟ้—ฎ ng_ai ๆ ธๅฟƒๆจกๅ—

asciiarmor

          โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
          โ”‚   Spark Cluster                                   โ”‚
          โ”‚    .โ”€โ”€โ”€โ”€โ”€.    .โ”€โ”€โ”€โ”€โ”€.    .โ”€โ”€โ”€โ”€โ”€.    .โ”€โ”€โ”€โ”€โ”€.       โ”‚
          โ”‚   ;       :  ;       :  ;       :  ;       :      โ”‚
       โ”Œโ”€โ–ถโ”‚   :       ;  :       ;  :       ;  :       ;      โ”‚
       โ”‚  โ”‚    โ•ฒ     โ•ฑ    โ•ฒ     โ•ฑ    โ•ฒ     โ•ฑ    โ•ฒ     โ•ฑ       โ”‚
       โ”‚  โ”‚     `โ”€โ”€โ”€'      `โ”€โ”€โ”€'      `โ”€โ”€โ”€'      `โ”€โ”€โ”€'        โ”‚
  Algo Spark                                                  โ”‚
    Engineโ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
       โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
       โ””โ”€โ”€โ”ค                                                    โ”‚          โ”‚
          โ”‚   NebulaGraph AI Suite(ngai)                       โ”‚ ngai-api โ”‚โ—€โ”€โ”
          โ”‚                                                    โ”‚          โ”‚  โ”‚
          โ”‚                                                    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค  โ”‚
          โ”‚     โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”Œโ”€โ”€โ”€โ”€โ”€โ”            โ”‚  โ”‚
          โ”‚     โ”‚ Reader โ”‚    โ”‚ Algo โ”‚    โ”‚ Writer โ”‚   โ”‚ GNN โ”‚            โ”‚  โ”‚
 โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ถโ”‚     โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ””โ”€โ”€โ”€โ”€โ”€โ”˜            โ”‚  โ”‚
 โ”‚        โ”‚          โ”‚            โ”‚            โ”‚          โ”‚               โ”‚  โ”‚
 โ”‚        โ”‚          โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”        โ”‚  โ”‚
 โ”‚        โ”‚          โ–ผ                โ–ผ              โ–ผ           โ–ผ        โ”‚  โ”‚
 โ”‚        โ”‚   โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚  โ”‚
 โ”‚     โ”Œโ”€โ”€โ”ค   โ”‚ SparkEngine โ”‚ โ”‚ NebulaEngine โ”‚ โ”‚ NetworkX โ”‚ โ”‚ DGLEngineโ”‚  โ”‚  โ”‚
 โ”‚     โ”‚  โ”‚   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚  โ”‚
 โ”‚     โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
 โ”‚     โ”‚             โ”‚        Spark                                          โ”‚
 โ”‚     โ”‚             โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€Reader โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”                           โ”‚
 โ”‚  Spark                   Query Mode           โ”‚                           โ”‚
 โ”‚  Reader                                       โ”‚                           โ”‚
 โ”‚Scan Mode                                      โ–ผ                      โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
 โ”‚     โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค ngai-udfโ”‚โ—€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
 โ”‚     โ”‚  โ”‚                                                   โ”‚         โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค              โ”‚
 โ”‚     โ”‚  โ”‚  NebulaGraph Graph Engine         Nebula-GraphD   โ”‚   ngai-GraphD     โ”‚              โ”‚
 โ”‚     โ”‚  โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜              โ”‚
 โ”‚     โ”‚  โ”‚                              โ”‚                    โ”‚                                  โ”‚
 โ”‚     โ”‚  โ”‚  NebulaGraph Storage Engine  โ”‚                    โ”‚                                  โ”‚
 โ”‚     โ”‚  โ”‚                              โ”‚                    โ”‚                                  โ”‚
 โ”‚     โ””โ”€โ–ถโ”‚  Nebula-StorageD             โ”‚    Nebula-Metad    โ”‚                                  โ”‚
 โ”‚        โ”‚                              โ”‚                    โ”‚                                  โ”‚
 โ”‚        โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                                  โ”‚
 โ”‚                                                                                               โ”‚
 โ”‚    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
 โ”‚    โ”‚ RETURN ng_ai("pagerank", ["follow"], ["degree"], "spark", {space:"basketballplayer"}) โ”‚โ”€โ”€โ”˜
 โ”‚    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
 โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
 โ”‚  โ”‚ from ng_ai import NebulaReader                              โ”‚
 โ”‚  โ”‚                                                             โ”‚
 โ”‚  โ”‚ # read data with spark engine, scan mode                    โ”‚
 โ”‚  โ”‚ reader = NebulaReader(engine="spark")                       โ”‚
 โ”‚  โ”‚ reader.scan(edge="follow", props="degree")                  โ”‚
 โ””โ”€โ”€โ”‚ df = reader.read()                                          โ”‚
    โ”‚                                                             โ”‚
    โ”‚ # run pagerank algorithm                                    โ”‚
    โ”‚ pr_result = df.algo.pagerank(reset_prob=0.15, max_iter=10)  โ”‚
    โ”‚                                                             โ”‚
    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜