iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 29
0
AI & Data

看圖說故事,讓 Neo4j 重新詮釋你的資料庫系列 第 29

以 GraphQL 查詢 Neo4j 資料庫

前言

GraphQL 與 Neo4j

GraphQL 原是 Facebook 內部的開發計畫,現已獨立出來成為 GraphQL 基金會。相較於 RESTful API,GraphQL 前端應用可以自定義每次查詢時,僅需要的部分資料欄位和範圍,後端也只需要回傳一小部分資料,藉此讓資料存取更有彈性、靈活和高效率。

GraphQL 的出現,並不是為了完全取代 REST,目前各式應用服務仍以 RESTful API 為最大宗,但是在前後端的資料存取組合愈趨複雜與多變時,RESTful API 便會不敷使用。

舉例來說,假設有一支 API 可以取得使用者的留言,那麼這就可以是一支 RESTful API。再來,除了留言本身圖文資料,我還想要看到有哪些人對它按讚(User LIKE Comment)、有哪些人分享了這則留言(User Share Comment)、有哪些人回覆了這一則留言(User Reply Comment)、以及這些回覆的留言內容(User Write Comment Reply Comment),以上的需求,如果要以 RESTful API 實作,就可能有幾種做法

  • 實作多支 API 來取得不同程度/深度的資料,API 職責分明
    但前端會需要為了一個需求,和後端互動多次,額外浪費許多連線與資料傳輸的時間
  • 只提供一支 API 讓前端呼叫,並提供參數化的查詢
    後端會需要在單一查詢中 JOIN 多個資料表,進行複雜的資料組合和運算,效率不佳。且為了在單一要求中保留前端應用的彈性,這支 API 會回傳大部分的欄位,即使前端根本不需要,這造成資料傳輸的浪費

有注意到上面的粗體字嗎?如果我們用 Cypher 語法來表達,就變成了

(u:User)-[:LIKE]->(c:Comment)
(u:User)-[:Share]->(c:Comment)
(u:User)-[:Reply]->(c:Comment)
(u:User)-[:Write]->(r:Comment)-[:Reply]->(c:Comment)

是不是覺得在這種多層次的複雜查詢應用上,用 Graph 來表達特別強大呢!

GraphQL 與 GraphDB

相較於 Cypher 是 Neo4j 資料庫的專屬查詢語言,GraphQL 則是開放性的查詢語言,其後端可以是關聯式資料庫。然而從上述的範例,應該隱約可以感受到,GraphQL + GraphDB 應該會是天作之合吧!

概念上來說,以之前的電影資料庫為例,以 Cypher 查詢某一部電影的演員如下

MATCH (m:Movie { title: 'The Matrix' })<-[:ACTION]-(p:Person)
RETURN m, p

以 GraphQL 來表達大概像是這樣

query {
   Movie(title:"The Matrix") {
      title
      released
      tagline
      actors {
         name
         born
      }
   }
}

對應的查詢結果

{
   "Movie": [{
      "title": "The Matrix",
      "released": 1999,
      "tagline": "Welcome to the Real World",
      "actors": [{
         "name": "Keanu Reeves",
         "born": 1964
         }, {
         "name": "Carrie-Anne Moss",
         "born": 1967
         }, {
         "name": "Laurence Fishburne",
         "born": 1961
         }
      ]
   }]
}

從上述語法可以看出,GraphQL 可以非常彈性且直覺的操作 GraphDB,且客製化回傳的做資料範圍。

安裝 Neo4j GraphQL plugin

如果你使用的是 Neo4j 3.5 或以前的版本,有個 GraphQL plugin 可以直接操作查詢 Neo4j 資料庫,如圖
(請注意 Neo4j 4.0 不支援 GraphQL plugin,這個 plugin 之後也不會再繼續維護和升級)

Neo4j GraphQL plugin

Neo4j Server 版的話,就是直接把下載的 jar 檔案複製到 plugins 資料夾底下,並重新啟動 Neo4j 即可
因為我想體驗一下 GraphQL plugin,所以用 Docker 的方式跑舊版的 Neo4j

docker run \
    --name egg_neo4j_3.5 \
    -p7474:7474 -p7687:7687 \
    -d --env NEO4J_AUTH=neo4j/mypassword \
    neo4j:3.5

docker cp neo4j-graphql-3.5.21.5.jar egg_neo4j_3.5:/var/lib/neo4j/plugins/

此外,還要修改 neo4j.conf

dbms.unmanaged_extension_classes=org.neo4j.graphql=/graphql

或是在上述的 docker run 指令加上參數

--env NEO4J_dbms_unmanaged__extension__classes=org.neo4j.graphql=/graphql

Neo4j 服務啟動後,記得在 browser 重新產生資料庫

:play movie graph

設定 GraphQL Schema

在操作 GraphQL 查詢之前,得先上傳 GraphQL Schema,有兩種做法
先假設我們的 Schema 如下

type Movie  {
  title: String!
  released: Int
  actors: [Person] @relation(name:"ACTED_IN",direction:IN)
}
type Person {
  name: String!
  born: Int
  movies: [Movie] @relation(name:"ACTED_IN")
}

第一種做法是在 GraphiQL POST http://localhost:7474/graphql/idl 並輸入上述的 Schema 內容,如果有設定密碼,記得也是要設定 HTTP Authorization Header
第二種做法是打開 Neo4j browser,呼叫預存程序 graphql.idl

CALL graphql.idl('
    type Movie  {
      title: String!
      released: Int
      tagline: String
      actors: [Person] @relation(name:"ACTED_IN",direction:IN)
    }
    type Person {
      name: String!
      born: Int
      movies: [Movie] @relation(name:"ACTED_IN")
    }
')

Neo4j GraphQL Change Schema

上傳 GraphQL schema 後,確定一下目前的 Schema

call graphql.schema()

Neo4j GraphQL Schema

接著就可以開始用 GraphQL 查詢 Neo4jDB

{ Person(name:"Kevin Bacon") {
    name
    born
    movies {
      title
      released
      tagline
    }
  }
}

Neo4j GraphiQL sample

GraphQL plugin 還可以進行許多進階查詢或修改資料,但 Neo4j 官方已不再支援維護,所以打算先體驗到這裡即可,之後再看看其他 GraphQL 的解決方案~

參考資源

https://github.com/neo4j-graphql/neo4j-graphql
https://grandstack.io/docs/neo4j-graphql-database-plugin/


上一篇
使用 Golang Driver 開發 Neo4j 應用程式
下一篇
Neo4j 的 GraphQL 計畫:GRANDstack
系列文
看圖說故事,讓 Neo4j 重新詮釋你的資料庫30

尚未有邦友留言

立即登入留言