有了 ETL 數據神器 dbt,表數據秒變 NebulaGraph 中的圖數據

語言: CN / TW / HK

本文搭配同主題分享視頻閲讀更佳,《多數據源的數據治理實踐》

如果你裝好某款數據庫產品,比如:分佈式圖數據庫 NebulaGrpah,躍躍欲試的第一步是不是就讓它幹活搞數據呢?好的,現在問題來了,如何把相對原始的數據處理、建模並導入 NebulaGraph 呢?本文是一個端到端的示例演示,從多數據源聚合數據,清理、利用 dbt 轉換成 NebulaGraph 建模的屬性圖點邊記錄,最後導入成圖譜的全流程。

構建知識圖譜

現在假設你是一個類似於 Netflix、愛奇藝之類的視頻服務提供商,我們需要利用圖數據庫搭建一個 用户-電影 的知識圖譜,來輔助、支撐視頻推薦、問答和推薦理由等常見由圖譜支撐的場景。由於時間的關係,這裏先用我們熟悉的老朋友——圖數據庫 NebulaGraph 來搞定知識圖譜。

一般來説,知識圖譜需要的數據會有不同的數據來源,比如一些公開的 API、數倉中的不同數據庫、靜態文件。這時候,我們如果要構建知識圖譜,需要以下 3 個步驟:

  1. 分析可能獲取的數據;
  2. 選取關心的關聯關係,圖建模;
  3. 抽取關聯關係,導入圖數據庫。

數據源

這裏我們會用到兩個數據源 OMDBMovieLens

OMDB 是一個開放的電影數據庫,將用來模擬公司內部的業務數據。我們可以獲得的信息有:

  • 電影
  • 電影的分類
  • 電影中的工作人員,包括:導演、動作指導、演員、後期製作等人員信息
  • 電影封面、宣傳片等電影信息

MovieLens 是一個開放的數據集,用來模擬公司內部的用户數據。我們可以獲得的信息有:

  • 用户
  • 電影
  • 用户對電影的評分交互

圖建模

在之前的文章《基於圖數據庫的推薦系統》 裏我們介紹了推薦系統的圖數據庫基本用法。在那篇文章中,內容過濾側重關注 用户-->電影電影-->分類電影-->演員電影-->導演 等關係,協同過濾則關注 用户-->電影 的關係,以及推薦理由服務關注以上所有的關係。

總結起來,我們需要的邊有:

  • watched(rate(double))
  • with_genre
  • directed_by
  • acted_by

結合已有信息,相對應地將頂點中可能需要被關注的信息作為屬性,給出點 tag 的初始規劃:

  • user(user_id)
  • movie(name)
  • person(name, birthdate)
  • genre(name)

schema_0

表數據到知識圖譜的映射

有了目標的圖譜結構定義,我們來看看手上的數據如何映射到它。

OMDB 數據

首先是 OMDB 數據,它由很多表組成,比如 all_movies 這張表,存儲了所有的電影、以及它們在不同語言下的名字:

movie_id name language_iso_639_1 official_translation
1 Cowboy Bebop de 1
1 Cowboy Bebop en 1
2 Ariel - Abgebrannt in Helsinki de 0
3 Shadows in Paradise en 0
3 Im Schatten des Paradieses de 0
3 Schatten im Paradies de 1

all_casts 表格中保有所有電影相關的工作人員:

movie_id person_id job_id role position
11 1 21 1
11 1 13 1
11 2 15 Luke Skywalker 1
11 3 15 Han Solo 3
11 4 15 Leia Organa 2

但是這裏的每一個人的姓名等信息、以及他/她在電影中任職的職位,則分別在表 job_namesall_people 中:

這裏講解下 job_names 表,1 代表編劇、2 代表製作人。有意思的是,和上表的電影 id 與 name 字段一樣,job_id 到 name 也是一對多的關係,因為 OMDB 中的數據都是多語言的。

job_id name language_iso_639_1
1 Autoren de
1 Writing Department en
1 Departamento de redacción es
1 Département écriture fr
1 Scenariusz pl
2 Produzenten de
2 Production Department en

下面這張表是 all_people

id name birthday deathday gender
1 George Lucas 1944-05-14 \N 0
2 Mark Hamill 1951-09-25 \N 0
3 Harrison Ford 1942-07-13 \N 0
4 Carrie Fisher 1956-10-21 2016-12-27 1
5 Peter Cushing 1913-05-26 1994-08-11 0
6 Anthony Daniels 1946-02-21 \N 0

這是在數據來源是表結構、RDBMS 中,是一個很典型的情況,所以對於 movie <-[directed_by]-(person) 這個關係,就涉及了 all_moviesall_castsall_peoplejob_names 四個表格:

  • directed_by
    • 起點 person_id 在 all_casts 之中
    • 終點 movie_id 在 all_casts 之中
      • 條件是 job_id 為 job_names 之中的 “director”
  • movie
    • person_id 在 all_casts 之中
    • 名字來自 all_movies 中按 id 查找,language 為 “en”
  • person
    • movie_id 在 all_casts 之中
    • name、birthday 在 all_people 之中

所有 OMDB 中我們關心的表的關聯如圖:

modeling_omdb

MovieLens 數據集

上面我們講述了單數據源的場景,只有單一數據源、數據表或者數倉的數據。但在真實場景中,我們還需要從其他源頭收取數據,並聚合起來。在本例中,我們還需要從 MovieLens 的數據集中抽取需要的知識。

這裏,涉及到 MovieLens 數據集,我們利用的只有:用户-->電影,這一條關係。

movies.csv 數據:

movieId title genres
1 Toy Story (1995) Adventure
2 Jumanji (1995) Adventure
3 Grumpier Old Men (1995) Comedy
4 Waiting to Exhale (1995) Comedy

ratings.csv 數據:

userId movieId rating timestamp
1 1 4 964982703
1 3 4 964981247
1 6 4 964982224

從兩個表的數據預覽似乎可以得出:

  • watched
    • 起點來自於 ratings.csv 中的 userId
    • 終點來自於 ratings.csv 中的 movieId
    • 評分來自於 ratings.csv 中的 rating
  • user
    • 來自於 ratings.csv 中的 userId

然而,細心的你們一定發現 MovieLens 數據集中的 movieId 和來自於 OMDB 中的電影 id 完全是不同的兩套體系。如果我們需要讓它們關聯起來,需要將 MovieLens 裏的 movieId 轉換成為 OMDB 中的電影 id,而它們之間的關聯條件則是電影的標題。

但是,通觀察我們知道:

  1. OMDB 電影中標題是多語言的
  2. MovieLens 中的標題結尾帶有(1995)這樣的年份信息

所以我們最終的結論為

  • watched
    • 起點來自於 ratings.csv 中的 userId
    • 終點來自於 ratings.csv 中的 movieId,終點要從 movies.csv 中的 title ,在 OMDB 之中查找,得到 OMDB 的 movie_id。查找條件為去掉年份,從 OMDB 的英文標題中進行匹配
    • 評分來自於 ratings.csv 中的 rating
  • user
    • 來自於 ratings.csv 中的 userId

現在,這個表格之間的關係如下

modeling_omdb_movielens

映射數據到圖譜(屬性圖)

到這裏小結下,我們需要對多個數據源中的不同表格(或者表格形式的 CSV 文件)進行聚合,這樣的對應關係如圖所示:藍色虛線表示圖中頂點的數據信息來源,粉色虛線表示邊信息的來源。

schema_mapping_to_graph

此外,我們還要對不同表中個體的 id 進行格式化,比如 user_id,是自增的數字,我們要轉換成全局唯一的 vertex_id。比較方便的方法是在現有 id 的基礎上增加字符串前綴,比如 u_

最終,以 user -[watched]-> movie 關係為例,我們可以處理得到這樣的表結構數據:

user_id rating title omdb_movie_id
u_1 5 Seven (a.k.a. Se7en) 807
u_1 5 Star Wars: Episode IV - A New Hope 11
u_1 5 Star Wars: Episode IV - A New Hope 10
u_1 4 Mask, The 832
u_1 3 Mrs. Doubtfire 832

其中每一行記錄中存在三個圖上的結構信息:

  • user 頂點 id
  • movie 頂點 id
  • watched 邊的 rating 值

數據工具

好的,我們現在已經完成了數據的分析與建模設計,在進入”抽取關聯關係,導入圖數據庫“環節之前,先介紹一下我們要用到的工具。

”抽取關聯關係“可以簡單認為是 ETL 中的 Extract 和 Transform。本質上就是工程上執行數據映射與轉換的工作,市面上有很多不同風格的工具、開源項目可以做 ETL 這件事。這裏我們用到我個人比較喜歡的工具:dbt

數據轉換利器 dbt

dbt 是一個開源的數據轉換工具,它有非常成熟的社區和生態,可以在大多數主流數倉之中進行高效、可控、高質量的數據轉換工作。無論是臨時的轉換工作(ad-hoc),還是在給定的定時 pipeline 中進行復雜編排,dbt 都可以很好勝任。它的一大特色就是使用 SQL LIKE 語言去描述數據轉換的規則。此外,它還基於 GitOps 可以非常優雅地多人協作、維護超大規模數據團隊裏複雜的數據處理作業。而 dbt 內置的數據測試能力可以很好地控制數據質量,可復現、控制數據問題。

dbt 不僅有許多集成的子項目,還能和像是 Meltano、Airflow、Amundsen、Superset 之類的優秀開源項目有機地結合,形成一整套現代的數據基礎設施體系。對具體實踐感興趣的同學可以閲讀文末「參考資料中」的數據治理實踐。

簡單來説,dbt 是一個 Python 寫的命令行工具。針對不同的項目,我們可以用 dbt 創建特定格式的項目文件夾,它會自帶一個 .yaml 配置文件。我們要在配置文件裏指定數據轉換的來源信息在哪裏,目標在哪裏(處理之後的數據存儲的地方,可能是 PostgreSQL、BigQuery、Spark 等)。在數據源中,我們用 yaml 文件和 .sql 文件一起描述了”從哪裏取哪些數據,如何做變換,輸出什麼“的信息。

starter-project-dbt-cli

這個截圖就是 dbt 官方文檔中的示例項目中的文件和配置,可以看到 models/example 裏的信息就是最核心的數據轉換 transform 的規則,而所有的其他數據都是和這個數據轉換相關的元數據,這些 dbt 項目文件非常適合用 git 來進行維護,進行現代、自動化的 DataOps。

NebulaGraph 數據導入

經過 dbt 對數據進行處理之後,我們可以得到直接映射到不同類型的頂點、邊、及其屬性的表結構的中間數據,它們可以是 CSV 的文件形式,也可以是數倉中的表,甚至可能是 Spark 中的 DataFrame。而將它們導入 NebulaGraph 有不同的選擇,可以選數據導入工具 NebulaGraph ExchangeNebulaGraph ImporterNebulaGraph Spark Connector 的任意一款。

在這裏,用最簡單的 NebulaGraph Importer 作為例子。

NebulaGraph Importer 是一個用 Golang 寫的開源數據工具。它可以編譯成一個單文件的二進制,通過預配置的 yaml 格式的文件,讀取指定 CSV 文件映射到 NebulaGraph 中點、邊關係數據。

實操

現在,我們來實操下如何利用 dbt + NebulaGraph Importer 進行多數據源聚合、轉換,再導入 NebulaGraph 的過程。整個項目的代碼已經開源,倉庫在 http://github.com/wey-gu/movie-recommendation-dataset 上,歡迎大家參考、共建。

整個實操過程如下:

  • 將源數據簡單清洗、導入數倉 PostgreSQL(EL)
  • 用 dbt 對數據進行轉換 Transform、導出為 CSV 文件
  • 用 NebulaGraph Importer 將 CSV 導入 NebulaGraph(L)

ETL_dbt_nebulagraph_importer

準備 dbt 環境

dbt 是一個 Python 項目,我們在一個虛擬的 Python 3 環境裏安裝好 dbt 和 dbt-postgres。

python3 -m venv .venv
source .venv/bin/activate
pip install dbt-postgres

創建一個 dbt 項目,並進入到空的項目裏:

dbt init dbt_project
cd dbt_project

看看裏邊的文件吧:

$ tree .
.
|-- README.md                      # 項目説明 README
|-- analyses
|-- dbt_project.yml                # 項目配置文件
|-- macros
|-- models                         # transform 來源
|   \-- example
|       |-- my_first_dbt_model.sql # 一個描述瞭如何從元數據中 SELECT 並處理的規則
|       |-- my_second_dbt_model.sql
|       \-- schema.yml             # 規則文件的元數據配置,描述了 sql 規則的屬性
|-- seeds                          # 源數據如果是 CSV 文件,可以放到 seeds 裏
|-- snapshots
\-- tests

7 directories, 5 files

最後,咱們拉一個容器裏的 Postgres 當做我們這個項目的數倉。如果你已經有各種其他數倉,就不需要這一步了,不過要把項目中的配置文件作相應的修改,並安裝相應的 dbt 插件。

docker run --rm --name postgres \
    -e POSTGRES_PASSWORD=nebula \
    -e POSTGRES_USER=nebula \
    -e POSTGRES_DB=warehouse -d \
    -p 5432:5432 postgres

數據下載與預處理

我們把數據放到項目的 raw_data 下吧。

mkdir -p raw_data
cd raw_data

注意,假設 raw_datadbt_proeject 之下:

tree ..
..
|-- README.md
|-- analyses
|-- dbt_project.yml
|-- macros
|-- models
|   \-- example
|       |-- my_first_dbt_model.sql
|       |-- my_second_dbt_model.sql
|       \-- schema.yml
|-- raw_data                       # 新建的目錄
|-- seeds
|-- snapshots
\-- tests

8 directories, 5 files

我們把 OMDB 數據下載之後,再解壓:

wget www.omdb.org/data/all_people.csv.bz2
wget www.omdb.org/data/all_people_aliases.csv.bz2
wget www.omdb.org/data/people_links.csv.bz2
wget www.omdb.org/data/all_casts.csv.bz2
wget www.omdb.org/data/job_names.csv.bz2
wget www.omdb.org/data/all_characters.csv.bz2
wget www.omdb.org/data/movie_categories.csv.bz2
wget www.omdb.org/data/movie_keywords.csv.bz2
wget www.omdb.org/data/category_names.csv.bz2
wget www.omdb.org/data/all_categories.csv.bz2
wget www.omdb.org/data/all_movie_aliases_iso.csv.bz2
bunzip2 *.bz2

然後是 MovieLens 數據集的下載、解壓:

wget http://files.grouplens.org/datasets/movielens/ml-latest-small.zip
unzip ml-latest-small.zip
rm *.zip

在導入數倉進行轉換 Transform 之前我們做一些數據的預處理,把它們放到 seeds 之下。

# 因為是實驗項目,我們簡單粗暴地去掉帶有轉義的引號的數據,因為它們會被認為是無效字符,處理之後的結果放到 seeds 下邊。
grep -v '\\"' raw_data/all_movie_aliases_iso.csv > seeds/all_movie_aliases_iso.csv
grep -v '\\"' raw_data/all_casts.csv > seeds/all_casts.csv
grep -v '\\"' raw_data/all_characters.csv > seeds/all_characters.csv
grep -v '\\"' raw_data/all_people.csv > seeds/all_people.csv
grep -v '\\"' raw_data/category_names.csv > seeds/category_names.csv
grep -v '\\"' raw_data/job_names.csv > seeds/job_names.csv
# 下邊的文件無需處理,直接放到 seeds 下邊。
cp raw_data/movie_categories.csv seeds/movie_categories.csv
cp raw_data/movie_keywords.csv seeds/movie_keywords.csv
cp raw_data/all_categories.csv seeds/all_categories.csv
cp raw_data/ml-latest-small/ratings.csv seeds/movielens_ratings.csv
cp raw_data/ml-latest-small/movies.csv seeds/movielens_movies.csv

有了 seeds 下邊的文件之後,可以用一個命令把他們導入到數倉裏:

dbt seed

執行過程因數倉而異,用本地的 Postgres 可能要等一會兒才能完成,執行結果大概是這樣的:

$ dbt seed
05:58:27  Running with dbt=1.3.0
05:58:27  Found 2 models, 4 tests, 0 snapshots, 0 analyses, 289 macros, 0 operations, 11 seed files, 0 sources, 0 exposures, 0 metrics
05:58:28  
05:58:28  Concurrency: 8 threads (target='dev')
05:58:28  
05:58:28  1 of 11 START seed file public.all_casts ....................................... [RUN]
...
07:10:11  1 of 11 OK loaded seed file public.all_casts ................................... [INSERT 1082228 in 4303.78s]
07:10:11  
07:10:11  Finished running 11 seeds in 1 hours 11 minutes and 43.93 seconds (4303.93s).
07:10:11  
07:10:11  Completed successfully
07:10:11  
07:10:11  Done. PASS=11 WARN=0 ERROR=0 SKIP=0 TOTAL=11

撰寫 Transform model

我們創建 model 如下:

mkdir models/movie_recommedation
touch models/movie_recommedation/user_watched_movies.sql
touch models/movie_recommedation/schema.yml

這時候 models 中的文件結構大概是這樣的:

$ tree models
models
\-- movie_recommedation
    |-- user_watched_movies.sql
    \-- schema.yml

這個 model 下邊目前只有一個規則,就是負責處理用户觀看電影這條邊上數據的 SQL 語句。

我們希望輸出三列,所以 schema.yml 中的內容是:

version: 2

models:
  - name: user_watched_movies
    description: "The edges between users and movies they have watched"
    columns:
      - name: user_id
        description: "user id"
        tests:
          - not_null
      - name: movie_id
        description: "movie id"
        tests:
          - not_null
      - name: rating
        description: "rating given by user to movie"
        tests:
          - not_null

注意,這裏的 tests 的表達是對數據驗證、測試的約束。有了它,我可以用 dbt 輕鬆地對數據質量進行測試、驗收,比如:我們要求這裏的三個字段都是 not_null

然後,我們來寫 SQL 吧,user_watched_movies.sql

{{ config(materialized='table') }}

/*
 JOIN the movieielens_ratings table with the movieielens_movies table, and removing the movie title tailing the year of release
 */
WITH user_watched_movies AS(
    SELECT moveielens_ratings."userId",
        moveielens_ratings."movieId",
        moveielens_ratings.rating,
        REGEXP_REPLACE(moveielens_movies.title, ' \(\d{4}\)$', '') AS title,
        moveielens_movies.genres AS movielens_genres
    FROM moveielens_ratings
        JOIN moveielens_movies ON moveielens_movies."movieId" = moveielens_ratings."movieId"
)
/* 
 JOIN user_watched_movies table with all_movie_aliase_iso table where language is English
 the join condition is the movie title
 */
SELECT concat('u_',user_watched_movies."userId") AS user_id,
    user_watched_movies.rating,
    user_watched_movies.title,
    all_movie_aliases_iso."movie_id" AS OMDB_movie_id,
    user_watched_movies.movielens_genres
FROM user_watched_movies
    JOIN all_movie_aliases_iso ON user_watched_movies.title LIKE CONCAT(all_movie_aliases_iso.name, '%')
    AND all_movie_aliases_iso.language_iso_639_1 = 'en'

而這個 SQL 做的事情就是綠色圓圈標註的部分:

  • movielens_ratings 中選 user id、movie id、rating、movie title(去掉年份),存成 user_watched_movies 的中間表格
    • movie title 從 movielens_movies JOIN ,通過 movie_id 相同的匹配條件取得
  • user_watched_movies 中選 user id(增加前綴 u_)、rating、title、OMDB_movie_id
    • OMDB_movie_id 從 all_movie_aliases_isoJOIN,通過相似的電影姓名匹配 OMDB 電影中英文標題取得
    • 最終的字段作為輸出

transform_select_joins_user_watched_movies

當然,我們可以在 Postgres 的連接器中通過增加 LIMIT 快速調試自己的 SQL 語句。

現在我們來通過 dbt 執行、測試剛剛的規則:

dbt run -m user_watched_movies

之後,我們應該就可以在 Postgres(數倉)中看到我們轉換之後的一個表了。

類似的,如法炮製所有其他部分的 Transform 規則,我們就獲得了這麼多 model 了:

$ tree models
models
\-- movie_recommedation
    |-- acted_by.sql
    |-- directed_by.sql
    |-- genres.sql
    |-- movies.sql
    |-- people.sql
    |-- schema.yml
    |-- user_watched_movies.sql
    \-- with_genre.sql

再對他們分別執行 transform:

dbt run -m acted_by
dbt run -m directed_by
dbt run -m with_genre
dbt run -m people
dbt run -m genres
dbt run -m movies

導出數據為 CSV

實際上,NebulaGraph Exchange 本身就支持把很多數據源(Postgres,ClickHouse,MySQL,Hive 等等)導入 NebulaGraph。只是在這個例子中,我們處理的數據量對於 NebulaGraph 來説非常非常小(只有百萬級別的邊而已),所以使用最輕量級的 NebulaGraph Importer 就足夠了。而 NebulaGraph Importer 能消費的數據只有 CSV 文件,所以我們把剛才的表都輸出為文件。

首先,我們進入 Postgres 的 Console,執行 COPY 命令

COPY acted_by TO '/tmp/acted_by.csv'  WITH DELIMITER ',' CSV HEADER;
COPY directed_by TO '/tmp/directed_by.csv'  WITH DELIMITER ',' CSV HEADER;
COPY with_genre TO '/tmp/with_genre.csv'  WITH DELIMITER ',' CSV HEADER;
COPY people TO '/tmp/people.csv'  WITH DELIMITER ',' CSV HEADER;
COPY movies TO '/tmp/movies.csv'  WITH DELIMITER ',' CSV HEADER;
COPY genres TO '/tmp/genres.csv'  WITH DELIMITER ',' CSV HEADER;
-- 對於 user_watched_movies 我們不輸出表頭,因為這個文件中記錄了兩種點、一種邊,沒法讓 importer 通過約定好的表頭自動導入,只能通過無表頭的情況下指定第幾列對應什麼字段
COPY user_watched_movies TO '/tmp/user_watched_movies.csv'  WITH DELIMITER ',' CSV;

再把 Postgres 容器裏的文件導入到 to_nebulagraph 這個文件夾裏:

mkdir -p to_nebulagraph
docker cp postgres:/tmp/. to_nebulagraph/

導入 NebulaGraph

創建 NebulaGraph 集羣

我們可以用 Nebula Up 一鍵拉起一個測試的 NebulaGraph 單機集羣,導入所需數據:

curl -fsSL nebula-up.siwei.io/install.sh | bash

創建 Schema

首先,我們創建一個叫做 moviegraph 的圖空間。針對前面的建模,創建點邊類型的結構 Schema:

先進入 NebulaGraph 的 Console:

~/.nebula-up/console.sh

再執行如下 DDL(Data Definiation Language):

CREATE SPACE moviegraph(partition_num=10,replica_factor=1,vid_type=fixed_string(32));
:sleep 20
USE moviegraph;
CREATE TAG person(name string, birthdate string);
CREATE TAG movie(name string);
CREATE TAG genre(name string);
CREATE TAG user(user_id string);
CREATE EDGE acted_by();
CREATE EDGE directed_by();
CREATE EDGE with_genre();
CREATE EDGE watched(rate float);
exit

創建 NebulaGraph Importer 配置文件

這個文件是一個描述 CSV 文件和集羣中點邊數據對應關係的 YAML 文件。詳細的格式可以參考文檔:http://docs.nebula-graph.com.cn/master/nebula-importer/use-importer/,或者視頻教程:http://www.bilibili.com/video/BV1ny4y1u7i4

最終的配置文件我已經為大家寫好了,在 http://github.com/wey-gu/movie-recommendation-dataset/blob/main/nebula-importer.yaml 可以下載得到。

這裏,我們就直接下載我寫好了的配置文件。注意,這個文件不應該是 dbt 項目文件的一部分,所以我們退出目錄,向上一層,把它放到 dbt_proeject 外邊:

cd ..
wget http://raw.githubusercontent.com/wey-gu/movie-recommendation-dataset/main/nebula-importer.yaml

開始導入

這一步,我們用容器化的 NebulaGraph Importer,避免了安裝的步驟:

docker run --rm -ti \
    --network=nebula-net \
    -v ${PWD}:/root/ \
    -v ${PWD}/dbt_project/to_nebulagraph/:/data \
    vesoft/nebula-importer:v3.2.0 \
    --config /root/nebula-importer.yaml

很快,所有的數據就導入到 NebulaGraph 之中了。現在,我們可以通過 NebulaGraph Console,執行一些查詢看看結果:

進入 Console:

~/.nebula-up/console.sh

進入圖空間、執行 SHOW STATS

USE moviegraph;
SHOW STATS;

結果:

(root@nebula) [moviegraph]> SHOW STATS;
+---------+---------------+---------+
| Type    | Name          | Count   |
+---------+---------------+---------+
| "Tag"   | "genre"       | 14397   |
| "Tag"   | "movie"       | 20701   |
| "Tag"   | "person"      | 263907  |
| "Tag"   | "user"        | 610     |
| "Edge"  | "acted_by"    | 673763  |
| "Edge"  | "directed_by" | 101949  |
| "Edge"  | "watched"     | 31781   |
| "Edge"  | "with_genre"  | 194009  |
| "Space" | "vertices"    | 299615  |
| "Space" | "edges"       | 1001502 |
+---------+---------------+---------+
Got 10 rows (time spent 1693/15136 us)

通過 NebulaGraph Studio,我們也可以在可視化界面探索這個圖譜。比如:在其中執行這個查詢,看一下給用户 u_124 推薦電影 1891 的理由可能是什麼?

FIND NOLOOP PATH FROM "u_124" TO "1891" over * BIDIRECT UPTO 4 STEPS yield path as `p` | LIMIT 20

它的結果是:曾經喜歡的星戰電影的大部分演職人員都也參與了這部同樣是“奧斯卡獲獎”且“經典”的電影。

reasoning_movie

總結

當我們打算把海量數據利用圖數據庫的能力進行知識轉化、洞察分析的時候,往往第一步就是要做多數據源到圖數據的轉換、處理、建模。對於無從下手的新手們來説,一個可行的思路是從所有的相關信息出發,去設想最關注的關聯關係,把邊寫出來,然後再羅列可以取得的點、以及需要的點、邊上的屬性。確定了初始的建模之後,就可以利用 ETL 工具把原始的數據清洗、ETL 成點、邊類型的表結構,最後,利用導入工具導入 NebulaGraph。

藉助於 dbt,我們可以版本控制、測試、迭代建模與數據轉換,一點點進化、豐富構建的知識圖譜。

參考資料


謝謝你讀完本文 (///▽///)

要來近距離快速體驗一把圖數據庫嗎?現在可以用用 NebulaGraph Cloud 來搭建自己的圖數據系統喲,快來節省大量的部署安裝時間來搞定業務吧~ NebulaGraph 阿里雲計算巢現 30 天免費使用中,點擊鏈接來用用圖數據庫吧~

想看源碼的小夥伴可以前往 GitHub 閲讀、使用、(^з^)-☆ star 它 -> GitHub;和其他的 NebulaGraph 用户一起交流圖數據庫技術和應用技能,留下「你的名片」一起玩耍呢~