GremlinクエリをCypherクエリに変換出来ないかなぁと調べているんだけど、まずサンプルが無いとどうにもならんので集めた。以下のように記述してあります。
- 日本語の説明 [Explanation in English]
Gremlin Query
Cypher Query
- 【全件取得】[Retrieve All]
- 【単一プロパティでのフィルタ】[Filter by single property]
- 【隣接頂点の取得(方向指定)】[Retrieve Adjacent Vertices (Specify Direction)]
- 【繰り返し探索(repeat/emit/until)】[Repeat Traversal (repeat/emit/until)]
- 【プロパティ操作(取得・更新・集約)】[Property Operations (Retrieve/Update/Aggregate)]
- 【集約とグルーピング】[Aggregation and Grouping]
- 【結合・選択・投影】[Join・Select・Projection]
- 【高度なパス探索と制御】[Advanced Path Exploration and Control]
- 【sideEffect/ロギング/ストア】[sideEffect/Logging/Store]
- 【順序付けと制限】 [Ordering and Limiting]
- 【map/flatMap/inject/reduce】 [map/flatMap/inject/reduce]
- 【プロジェクションと複合出力】 [Projection and Composite Output]
- 【都市・会社など特定属性の例】 [Examples of Specific Attributes like City/Company]
- 【store・aggregateの利用例】 [Example of store and aggregate]
- 【optional・where・filterの利用例】 [Example of optional, where, and filter]
- 【order, dedup, simplePath】 [order, dedup, simplePath]
- 【inject / loops / coalesce の利用例】 [Examples of inject, loops, and coalesce]
- 【さらに複雑なパス探索例】 [More complex path exploration examples]
- 【グラフ内の特定の関係性の例】 [Examples of specific relationships in the graph]
- 【側面出力(sideEffect)とデバッグ】 [SideEffect and Debugging]
- 【withSideEffectの利用例】 [Examples of withSideEffect]
- 【グルーピング応用例】[Examples of Grouping]
- 【foldとcoalesceの組み合わせ】 [Combination of fold and coalesce]
【全件取得】[Retrieve All]
- すべての頂点を取得する [Retrieve all vertices]
g.V()
MATCH (n) RETURN n - すべての辺を取得する [Retrieve all edges]
g.E()
MATCH ()-[e]-() RETURN e
【単一プロパティでのフィルタ】[Filter by single property]
- 「name」プロパティが “Alice” の頂点を取得する [Retrieve vertices where the “name” property is “Alice”]
g.V().has(“name”, “Alice”)
MATCH (n) WHERE n.name = ‘Alice’ RETURN n - 「age」プロパティが 30 より大きい頂点を取得する [Retrieve vertices where the “age” property is greater than 30]
g.V().has(“age”, gt(30))
MATCH (n) WHERE n.age > 30 RETURN n - 「age」プロパティが 20〜40の間にある頂点を取得する [Retrieve vertices where the “age” property is between 20 and 40]
g.V().has(“age”, between(20, 40))
MATCH (n) WHERE n.age >= 20 AND n.age <= 40 RETURN n - 「name」プロパティが “Alice”, “Bob”, “Charlie” のいずれかに一致する頂点を取得する [Retrieve vertices where the “name” property is one of “Alice”, “Bob”, or “Charlie”]
g.V().has(“name”, within(“Alice”, “Bob”, “Charlie”))
MATCH (n) WHERE n.name IN [‘Alice’, ‘Bob’, ‘Charlie’] RETURN n - 「occupation」プロパティが “programmer” ではない頂点を取得する [Retrieve vertices where the “occupation” property is not “programmer”]
g.V().has(“occupation”, neq(“programmer”))
MATCH (n) WHERE n.occupation <> ‘programmer’ RETURN n - 正規表現を用いて、nameが “A” で始まる頂点を取得する [Retrieve vertices where the “name” property starts with “A” using a regular expression]
g.V().has(“name”, regex(“A.”)) MATCH (n) WHERE n.name =~ ‘A.’ RETURN n
【隣接頂点の取得(方向指定)】[Retrieve Adjacent Vertices (Specify Direction)]
- 頂点「Alice」から外向きの隣接頂点を取得する [Retrieve adjacent vertices from vertex ‘Alice’ in the outward direction]
g.V().has(“name”, “Alice”).out()
MATCH (n {name: ‘Alice’})-[]->(m) RETURN m - 頂点「Alice」から内向きの隣接頂点を取得する [Retrieve adjacent vertices from vertex ‘Alice’ in the inward direction]
g.V().has(“name”, “Alice”).in()
MATCH (n {name: ‘Alice’})<-[]-(m) RETURN m - 頂点「Alice」から両方向の隣接頂点を取得する [Retrieve adjacent vertices from vertex ‘Alice’ in both directions]
g.V().has(“name”, “Alice”).both()
MATCH (n {name: ‘Alice’})-[]-(m) RETURN m - 頂点「Alice」から「knows」エッジに沿った両方向の隣接頂点を取得する [Retrieve adjacent vertices from vertex ‘Alice’ along the ‘knows’ edge in both directions]
g.V().has(“name”, “Alice”).bothE(“knows”).otherV()
MATCH (n {name: ‘Alice’})-[e:knows]-(m) RETURN m - 頂点「Alice」から外向き「knows」エッジをたどり隣接頂点を取得する [Retrieve adjacent vertices from vertex ‘Alice’ along the ‘knows’ edge in the outward direction]
g.V().has(“name”, “Alice”).out(“knows”)
MATCH (n {name: ‘Alice’})-[:knows]->(m) RETURN m - 頂点「Alice」から外向き「created」エッジをたどり、かつ先の頂点の「lang」が “java” であるものを取得する [Retrieve adjacent vertices from vertex ‘Alice’ along the ‘created’ edge in the outward direction where the language is ‘java’]
g.V().has(“name”, “Alice”).out(“created”).has(“lang”, “java”)
MATCH (n {name: ‘Alice’})-[:created]->(m {lang: ‘java’}) RETURN m - 頂点「Alice」から外向き(“knows”)エッジを3回辿り、重複を除いた頂点リストを取得する [Retrieve adjacent vertices from vertex ‘Alice’ along the ‘knows’ edge in the outward direction]
g.V().has(“name”, “Alice”).repeat(out(“knows”)).times(3).dedup()
MATCH (n {name: ‘Alice’})-[:knows*3]->(m) RETURN DISTINCT m
【繰り返し探索(repeat/emit/until)】[Repeat Traversal (repeat/emit/until)]
- 頂点「Alice」から外向きエッジを2回繰り返して到達する頂点を取得する [Retrieve vertices by traversing outward edges twice from vertex “Alice”]
g.V().has(“name”, “Alice”).repeat(out()).times(2)
MATCH (a {name: ‘Alice’})-[]->()-[]->(m) RETURN m - 頂点「Alice」から、どちらの方向(both)のエッジをたどり、条件(nameが “Bob”)に到達するまで繰り返す [Retrieve vertices by traversing both directions from vertex “Alice” until reaching a vertex with name “Bob”]
g.V().has(“name”, “Alice”).repeat(both()).until(has(“name”, “Bob”))
MATCH p = (a {name:’Alice’})-[*]-(b {name:’Bob’}) RETURN b - 頂点「Alice」から外向きエッジを繰り返し、年齢が 50 より大きい頂点に到達するまでのパスを取得する [Retrieve paths from vertex ‘Alice’ along the outward edges until reaching a vertex with age greater than 50]
g.V().has(“name”, “Alice”).repeat(out()).until(has(“age”, gt(50))).path()
MATCH p = (a {name:’Alice’})-[*]->(m) WHERE m.age > 50 RETURN p - 頂点「Alice」から外向き”knows”エッジを繰り返し、条件をemitしてすべての途中経路を取得する [Retrieve paths from vertex ‘Alice’ along the ‘knows’ edge in the outward direction, emitting intermediate paths]
g.V().has(“name”, “Alice”).repeat(out(“knows”)).emit().times(2)
MATCH (a {name: ‘Alice’}) MATCH (a)-[:knows*1..2]->(m) RETURN DISTINCT m - 頂点「Alice」からboth(“knows”)エッジを繰り返し、パス上のループを避けながら取得する [Retrieve paths from vertex ‘Alice’ along the ‘knows’ edge in both directions, avoiding loops]
g.V().has(“name”, “Alice”).repeat(both(“knows”).simplePath()).until(has(“name”, “Charlie”)).path()
MATCH p = (a {name: ‘Alice’})-[:knows*]-(c {name: ‘Charlie’}) WHERE ALL(n IN nodes(p) WHERE SINGLE(x IN nodes(p) WHERE x = n)) RETURN p
【プロパティ操作(取得・更新・集約)】[Property Operations (Retrieve/Update/Aggregate)]
- 頂点「Alice」の「age」プロパティの値を取得する [Retrieve the value of the ‘age’ property of vertex ‘Alice’]
g.V().has(“name”, “Alice”).values(“age”)
MATCH (n {name: ‘Alice’}) RETURN n.age - 頂点「Alice」のすべてのプロパティをマップ形式で取得する [Retrieve all properties of vertex ‘Alice’ in map form]
g.V().has(“name”, “Alice”).valueMap()
MATCH (n {name: ‘Alice’}) RETURN properties(n) AS valueMap - 頂点「Alice」に対し、「nickname」を “Ally” として設定する(変更操作の場合はiterate()で実行) [Set the ‘nickname’ property of vertex ‘Alice’ to ‘Ally’ (execute the change operation using iterate())]
g.V().has(“name”, “Alice”).property(“nickname”, “Ally”).iterate()
MATCH (n {name: ‘Alice’}) SET n.nickname = ‘Ally’ RETURN n - 頂点「Alice」の「age」プロパティを取得し、すべての値の合計を計算する [Retrieve the ‘age’ property of vertex ‘Alice’ and calculate the sum of all values]
g.V().has(“name”, “Alice”).values(“age”).sum()
MATCH (n {name: ‘Alice’}) RETURN sum(n.age) AS sumAge - 頂点「Alice」から出発し、隣接頂点の「age」プロパティをリストで取得する [Retrieve the ‘age’ property of adjacent vertices from vertex ‘Alice’ in a list]
g.V().has(“name”, “Alice”).out().values(“age”).fold()
MATCH (n {name: ‘Alice’})-[]->(m) RETURN collect(m.age) AS ages
【集約とグルーピング】[Aggregation and Grouping]
- グラフ上の全頂点の件数をカウントする [Count the total number of vertices in the graph]
g.V().count()
MATCH (n) RETURN count(n) AS count - 頂点を「country」プロパティ別にグループ分けし、各グループの件数を求める [Group vertices by ‘country’ property and count the number of vertices in each group]
g.V().group().by(“country”).by(count())
MATCH (n) RETURN n.country AS country, count(n) AS count - 頂点「person」ラベルの頂点を「name」と「age」でプロジェクトして取得する [Project vertices with the “person” label by “name” and “age”]
g.V().hasLabel(“person”).project(“name”, “age”).by(“name”).by(“age”)
MATCH (p:person) RETURN p.name AS name, p.age AS age - 頂点「Alice」から隣接頂点の性別ごとの件数を集計する [Count the number of adjacent vertices by gender starting from vertex ‘Alice’]
g.V().has(“name”, “Alice”).both().groupCount().by(“gender”)
MATCH (a {name: ‘Alice’})–(b) RETURN b.gender AS gender, count(b) AS count - 頂点「Alice」を起点に隣接頂点の性別ごとの平均年齢を集計する [Calculate the average age of adjacent vertices by gender starting from vertex ‘Alice’]
g.V().has(“name”, “Alice”).both().group().by(“gender”).by(mean(“age”))
MATCH (a {name: ‘Alice’})–(b) RETURN b.gender AS gender, avg(b.age) AS avgAge - グラフ全体の頂点をラベルごとにグルーピングし、各グループの件数を求める [Group all vertices in the graph by label and count each group]
g.V().group().by(label).by(count())
MATCH (n) RETURN head(labels(n)) AS label, count(n) AS count - 「post」頂点を「author」ごとにグループ分けし、件数をカウントする [Group “post” vertices by “author” and count each group]
g.V().has(“type”, “post”).group().by(“author”).by(count())
MATCH (n {type: ‘post’}) RETURN n.author AS author, count(n) AS count - 「post」頂点を「category」ごとにグループ化し、「likes」の合計を算出する [Group “post” vertices by “category” and sum the “likes” property]
g.V().has(“type”, “post”).group().by(“category”).by(sum(“likes”))
MATCH (n {type: ‘post’}) RETURN n.category AS category, sum(n.likes) AS totalLikes
【結合・選択・投影】[Join・Select・Projection]
- 頂点「Alice」と頂点「Bob」を個別に取得し、名前ペアとして選択する [Retrieve vertices “Alice” and “Bob” individually and select them as a name pair]
g.V().has(“name”, “Alice”).as(“a”).V().has(“name”, “Bob”).as(“b”).select(“a”, “b”).by(“name”)
MATCH (a {name: ‘Alice’}), (b {name: ‘Bob’}) RETURN a.name AS a, b.name AS b - 頂点「Alice」から「created」エッジに沿いソフトウェア頂点に移動し、エイリアスで取得する [Traverse from vertex “Alice” along the “created” edge to software vertices and select them with an alias]
g.V().has(“person”, “name”, “Alice”).outE(“created”).inV().as(“software”).select(“software”)
MATCH (a:person {name: ‘Alice’})-[:created]->(software) RETURN software - 頂点「Alice」の名前をaggregate()で一時リストに保存して取り出す [Save the name of vertex “Alice” to a temporary list using aggregate() and retrieve it]
g.V().has(“name”, “Alice”).aggregate(“aList”).by(“name”).cap(“aList”)
MATCH (n {name: ‘Alice’}) WITH collect(n.name) AS aList RETURN aList - 頂点「Alice」から左右の隣接頂点をunionで取得する(例:knowsとworksAt) [Retrieve adjacent vertices from vertex “Alice” using union (e.g., knows and worksAt)]
g.V().has(“name”, “Alice”).union(out(“knows”), out(“worksAt”)).dedup()
MATCH (a {name: ‘Alice’})-[:knows|worksAt]->(b) RETURN DISTINCT b - 頂点「Laptop」製品を購入したユーザ(入辺 “purchased”)を取得する [Retrieve users who purchased the “Laptop” product using the “purchased” edge]
g.V().has(“product”, “name”, “Laptop”).in(“purchased”).dedup()
MATCH (buyer)-[:purchased]->(p:product {name: ‘Laptop’}) RETURN DISTINCT buyer
【高度なパス探索と制御】[Advanced Path Exploration and Control]
- 頂点「Alice」からoutE()経由でinV()に進むパスを、visited属性が true になるまで探索する [Traverse paths from vertex “Alice” via outE() to inV() until the visited attribute is true]
g.V().has(“name”, “Alice”).repeat(outE().inV()).until(has(“visited”, true)).path()
MATCH path = (a {name: ‘Alice’})-[:*]->(b) WHERE exists(b.visited) AND b.visited = true RETURN path - 頂点「Alice」から、first-hopで出会った全隣接頂点のうち、simplePath()でループを排除する [Retrieve all adjacent vertices from vertex “Alice” at the first hop, excluding loops using simplePath()]
g.V().has(“name”, “Alice”).both().simplePath()
MATCH path = (a {name: ‘Alice’})-[*]-(b) WHERE length(path) = 1 RETURN path - 頂点「Alice」から、任意の隣接頂点をstore()で一時保存し、最後にその蓄積からdedupした結果を返す [Temporarily store adjacent vertices from vertex “Alice” using store() and return the deduplicated result]
g.V().has(“name”, “Alice”).store(“a”).out(“knows”).store(“a”).cap(“a”).dedup()
MATCH (a {name: ‘Alice’}) WITH a MATCH (a)-[:knows]->(b) WITH collect(a) + collect(b) AS aList UNWIND aList AS person RETURN DISTINCT person - 頂点「Alice」による「knows」エッジをfold()でまとめ、coalesceで結果をソート(エッジが無ければ定数を返す) [Traverse “knows” edges from vertex “Alice” using fold() and coalesce, returning a constant if no edges exist]
g.V().has(“name”, “Alice”).bothE(“knows”).fold().coalesce(unfold().order().by(“since”, asc), constant(“No knows edges”))
MATCH (a {name: ‘Alice’})-[r:knows]-() WITH collect(r) AS edges UNWIND edges AS edge RETURN edge ORDER BY edge.since ASC LIMIT 1 UNION RETURN “No knows edges” AS result LIMIT 1 - 頂点「Alice」からout(“knows”)エッジに沿って3ホップ辿り、パスを取得する [Traverse outward “knows” edges three times from vertex “Alice” and return the path]
g.V().has(“name”, “Alice”).repeat(out(“knows”)).times(3).dedup().path()
MATCH path = (a {name: ‘Alice’})-[:knows*3]->(b) RETURN DISTINCT path - match()を使い、Aliceが知っている人(aからb)で、さらにそのbが “java” で作成したものを持つ組を取得する [Use match() to retrieve pairs where Alice knows someone (a to b) and that person created something in “java”]
g.V().has(“name”, “Alice”).match(.as(“a”).out(“knows”).as(“b”),.as(“b”).out(“created”).has(“lang”, “java”)).select(“a”, “b”)
MATCH (a {name: ‘Alice’})-[:knows]->(b)-[:created]->(c {lang: ‘java’}) RETURN a, b - 頂点「Alice」から隣接して「worksAt」エッジをたどり、さらにその先の場所の「city」を取得する(optionalステップ) [Traverse from vertex “Alice” along the “worksAt” edge and retrieve the “city” property of the location (optional step)]
g.V().has(“name”, “Alice”).optional(out(“worksAt”).out(“locatedIn”)).values(“city”)
MATCH (a {name: ‘Alice’}) OPTIONAL MATCH (a)-[:worksAt]->()-[:locatedIn]->(location) RETURN location.city
【sideEffect/ロギング/ストア】[sideEffect/Logging/Store]
- 頂点「Alice」から出発し、到達した各頂点をsideEffectで出力する [Traverse from vertex “Alice” and output each reached vertex using sideEffect]
g.V().has(“name”, “Alice”).both().sideEffect{ println it }
MATCH (a {name: ‘Alice’})–(b) WITH b CALL apoc.do.when(b IS NOT NULL, ‘RETURN b’, ‘RETURN NULL’, {b: b}) YIELD value RETURN value.b - sideEffectで変数「x」に頂点IDを追加する(withSideEffectとsideEffectの組み合わせ) [Add vertex IDs to variable “x” using sideEffect (combination of withSideEffect and sideEffect)]
g.withSideEffect(“x”, []).V().has(“name”, “Alice”).sideEffect{ it.sideEffects[“x”] << it.id() }
WITH [] AS x MATCH (a {name: ‘Alice’}) WITH a, x + id(a) AS x RETURN x - 頂点「tag」が “urgent” のものを、assigneeごとにグループ化し、その件数を集計する [Group vertices with the “urgent” tag by assignee and count each group]
g.V().has(“tag”, “urgent”).group().by(“assignee”).by(count())
MATCH (n:tag {tag: ‘urgent’}) RETURN n.assignee AS assignee, count(n) AS count
【順序付けと制限】 [Ordering and Limiting]
- 頂点「person」ラベルの頂点を「name」プロパティで昇順ソートする [Sort vertices with the “person” label in ascending order by the “name” property]
g.V().hasLabel(“person”).order().by(“name”, asc)
MATCH (n:person) RETURN n ORDER BY n.name ASC - 頂点「person」ラベルを「age」プロパティで降順ソートする [Sort vertices with the “person” label in descending order by the “age” property]
g.V().hasLabel(“person”).order().by(“age”, desc)
MATCH (n:person) RETURN n ORDER BY n.age DESC - 頂点「Alice」を含む頂点を10件に制限して取得する [Limit vertices containing the vertex “Alice” to 10]
g.V().has(“name”, “Alice”).limit(10)
MATCH (n {name: ‘Alice’}) RETURN n LIMIT 10 - 辺を5件だけ取得する [Retrieve only 5 edges]
g.E().limit(5) MATCH ()-[e]->() RETURN e LIMIT 5
【map/flatMap/inject/reduce】 [map/flatMap/inject/reduce]
- inject()を使い、リスト[1,2,3,4,5]の合計を計算する [Calculate the sum of the list [1, 2, 3, 4, 5] using inject()]
g.inject(1, 2, 3, 4, 5).reduce(sum)
WITH [1, 2, 3, 4, 5] AS numbers RETURN reduce(total = 0, n IN numbers | total + n) AS sum - 頂点「Alice」のageをfold()でリスト化してから返す [Retrieve the age of vertex “Alice” as a list using fold()]
g.V().has(“name”, “Alice”).map(values(“age”).fold())
MATCH (n {name: ‘Alice’}) RETURN collect(n.age) AS age - 頂点「Alice」のプロパティをvalueMap()で取得し、そのマップを返す [Retrieve the properties of vertex “Alice” as a map using valueMap()]
g.V().has(“name”, “Alice”).map(valueMap())
MATCH (n {name: ‘Alice’}) RETURN properties(n) AS valueMap
【プロジェクションと複合出力】 [Projection and Composite Output]
- 頂点「Alice」の「name」と、両隣接頂点の名前リストをプロジェクトして取得する [Retrieve the name of vertex “Alice” and a list of names of its neighbors using projection]
g.V().has(“name”, “Alice”).project(“name”, “neighbors”).by(“name”).by(both(“knows”).values(“name”).fold())
MATCH (a {name: ‘Alice’}) RETURN a.name AS name, collect(DISTINCT b.name) AS neighbors MATCH (a)-[:knows]-(b) - 頂点「Alice」の両隣接頂点をグループ化して、その名前ごとに件数を調べる [Group both adjacent vertices of vertex “Alice” by name and count each group]
g.V().has(“name”, “Alice”).both(“knows”).group().by(“name”).by(count())
MATCH (a {name: ‘Alice’})-[:knows]-(b) RETURN b.name AS name, count(b) AS count - 頂点「Alice」から、out(“likes”)エッジを辿り、最初の3パスを取得する [Traverse outward “likes” edges from vertex “Alice” and retrieve the first 3 paths]
g.V().has(“name”, “Alice”).repeat(out(“likes”)).emit().path().limit(3)
MATCH path = (a {name: ‘Alice’})-[:likes*]->(b) WITH path LIMIT 3 RETURN path
【都市・会社など特定属性の例】 [Examples of Specific Attributes like City/Company]
- 「city」プロパティが “Tokyo” の頂点から、その city に関連する「livesIn」関係の隣接頂点を取得する [Retrieve adjacent vertices connected by “livesIn” edges from vertices with “city” property “Tokyo”]
g.V().has(“city”, “Tokyo”).out(“livesIn”).dedup()
MATCH (c {city: ‘Tokyo’})<-[:livesIn]-(p) RETURN DISTINCT p - 頂点「Alice」から、out(“created”)エッジを3回辿るパスを取得する [Traverse outward “created” edges three times from vertex “Alice” and return the path]
g.V().has(“name”, “Alice”).repeat(out(“created”)).times(3).path()
MATCH path = (a {name: ‘Alice’})-[:created*3]->(b) RETURN path - 頂点「Alice」から、out(“knows”)を辿って、条件(nameが「Charlie」)に到達するパスを取得する [Traverse outward “knows” edges from vertex “Alice” until reaching a vertex with name “Charlie” and return the path]
g.V().has(“name”, “Alice”).repeat(out(“knows”)).until(has(“name”, “Charlie”)).path()
MATCH path = (a {name: ‘Alice’})-[:knows*]->(b {name: ‘Charlie’}) RETURN path - 「software」頂点で、langが “java” のものを取得し、それを作成した人物をin(“created”)で取得する [Retrieve “software” vertices with “lang” property “java” and retrieve the creators using “created” edges]
g.V().hasLabel(“software”).has(“lang”, “java”).in(“created”).dedup()
MATCH (s:software {lang: ‘java’})<-[:created]-(p) RETURN DISTINCT p - 頂点「Alice」から、weightが 0.5 より大きいエッジを両方向探索する [Traverse outward and inward edges with “weight” property greater than 0.5 from vertex “Alice”]
g.V().has(“name”, “Alice”).bothE().has(“weight”, gt(0.5)).otherV()
MATCH (a {name: ‘Alice’})-[e]-(b) WHERE e.weight > 0.5 RETURN b - 頂点「Alice」のbothE(“knows”)エッジから、”since”プロパティが存在するものをフィルタする [Filter “knows” edges from vertex “Alice” where “since” property exists]
g.V().has(“name”, “Alice”).bothE(“knows”).filter(values(“since”).is(neq(null)))
MATCH (a {name: ‘Alice’})-[e:knows]-() WHERE e.since IS NOT NULL RETURN e
【store・aggregateの利用例】 [Example of store and aggregate]
- 頂点「Alice」から、knowsエッジを辿りながらvisitedフラグが付いている頂点をストアする [Store vertices with the “visited” flag while traversing from vertex “Alice” along “knows” edges.]
g.V().has(“name”, “Alice”).store(“visited”).repeat(out(“knows”)).until(has(“name”, “Bob”)).cap(“visited”)
MATCH (a {name: ‘Alice’}) WITH a, [a] AS visited MATCH path = (a)-[:knows*]->(b {name: ‘Bob’}) WITH nodes(path) AS allNodes, visited UNWIND allNodes AS node WITH collect(DISTINCT node) + visited AS allVisited RETURN allVisited AS visited - 頂点「Alice」から、3回の繰り返し探索後に、結果を名前順に並べ替える [Sort the result in ascending order by name after 3 iterations of traversal from vertex “Alice”]
g.V().has(“name”, “Alice”).repeat(both()).times(3).dedup().order().by(“name”, asc)
MATCH (a {name: ‘Alice’})-[*3]-(b) WITH DISTINCT b RETURN b ORDER BY b.name ASC
【optional・where・filterの利用例】 [Example of optional, where, and filter]
- 頂点「Alice」から、両隣接頂点を取得し、さらにその中でout(“worksAt”)が存在するものだけを返す [Retrieve vertices adjacent to “Alice” and return only those that have an outgoing “worksAt” edge]
g.V().has(“name”, “Alice”).both().optional(out(“worksAt”)).path()
MATCH path = (a {name: ‘Alice’})–(b) OPTIONAL MATCH (b)-[:worksAt]->(c) RETURN path - ラベルが “person” で、かつ out(“knows”)が存在しない頂点を取得する [Retrieve vertices with label “person” and no outgoing “knows” edge]
g.V().has(“person”).where(not(out(“knows”)))
MATCH (p:person) WHERE NOT (p)-[:knows]->() RETURN p - 頂点「person」ラベルから、out(“created”)の数が1つより多いものをフィルタする [Filter vertices with label “person” and more than one outgoing “created” edge]
g.V().hasLabel(“person”).filter(out(“created”).count().is(gt(1)))
MATCH (p:person) WHERE size((p)-[:created]->()) > 1 RETURN p - 頂点「Alice」から、out(“knows”)で “Bob” という名前の頂点と接続しているかどうかを調べる
g.V().has(“name”, “Alice”).out(“knows”).has(“name”, “Bob”)
MATCH (a {name: ‘Alice’})-[:knows]->(b {name: ‘Bob’}) RETURN b
【order, dedup, simplePath】 [order, dedup, simplePath]
- 頂点「Alice」から bothE(“knows”)を辿り、エッジを「since」で降順ソートして上位2件を取得する [From vertex “Alice”, traverse “knows” edges and retrieve the top 2 edges sorted by the “since” property in descending order]
g.V().has(“name”, “Alice”).bothE(“knows”).order().by(“since”, desc).limit(2)
MATCH (a {name: ‘Alice’})-[e:knows]-() RETURN e ORDER BY e.since DESC LIMIT 2 - 頂点「Alice」から両隣接頂点の「city」プロパティを取得し、重複を除去する [Retrieve the “city” property of vertices adjacent to “Alice” via “knows” edges and remove duplicates]
g.V().has(“name”, “Alice”).both(“knows”).values(“city”).dedup()
MATCH (a {name: ‘Alice’})-[:knows]-(b) RETURN DISTINCT b.city
【inject / loops / coalesce の利用例】 [Examples of inject, loops, and coalesce]
- inject()で “hi”, “hello”, “hey” を返す [Using inject to return “hi”, “hello”, “hey”]
g.inject(“hi”, “hello”, “hey”)
UNWIND [‘hi’, ‘hello’, ‘hey’] AS greeting RETURN greeting - 頂点「Alice」から out(“created”)を辿り、ループ回数が2回目の結果をフィルタする [Using repeat to traverse “created” edges and filter the result at the 2nd loop]
g.V().has(“name”, “Alice”).repeat(out(“created”)).loops().is(2)
MATCH (a {name: ‘Alice’})-[:created*2]->(b) RETURN b - repeatとcoalesceを組み合わせ、knowsエッジがなければ定数 “No link” を返す [Using repeat and coalesce to return “No link” if no “knows” edges are found]
g.V().has(“name”, “Alice”).bothE(“knows”).fold().coalesce(unfold().order().by(“since”, asc), constant(“No link”))
MATCH (a {name: ‘Alice’})-[e:knows]-() WITH collect(e) AS edges RETURN CASE WHEN size(edges) > 0 THEN head([edge IN edges | edge ORDER BY edge.since ASC]) ELSE “No link” END AS result
【さらに複雑なパス探索例】 [More complex path exploration examples]
- 頂点「Alice」から outE(“knows”)→inV()を3回辿るパスを取得する [Retrieve a path from vertex “Alice” by traversing outgoing “knows” edges three times]
g.V().has(“name”, “Alice”).repeat(outE(“knows”).inV()).times(3).dedup().path()
MATCH path = (a {name: ‘Alice’})-[:knows*3]->(b) RETURN DISTINCT path - 頂点「Alice」からout(“likes”)を辿り、到達した中でpopularityが100を超えるものだけを返す [Retrieve a path from vertex “Alice” by traversing outgoing “likes” edges four times, returning only those with a popularity greater than 100]
g.V().has(“name”, “Alice”).repeat(out(“likes”)).times(4).where(has(“popularity”, gt(100))).path()
MATCH path = (a {name: ‘Alice’})-[:likes*4]->(b) WHERE b.popularity > 100 RETURN path - 頂点「Alice」からboth()エッジで2ホップ以内の頂点を取得する(simplePathでループ排除) [Retrieve vertices within 2 hops from “Alice” using both() edges, ensuring no loops with simplePath.]
g.V().has(“name”, “Alice”).repeat(both().simplePath()).times(2).dedup()
MATCH (a {name: ‘Alice’})-[*2]-(b) WHERE all(r IN relationships(path) WHERE size(nodes(path)) = size(apoc.coll.toSet(nodes(path)))) RETURN DISTINCT b
【グラフ内の特定の関係性の例】 [Examples of specific relationships in the graph]
- 「city」が “New York” の頂点から、”livesIn” エッジに沿って接続している頂点の件数をカウントする [Count the number of vertices connected to vertices with the “city” property set to “New York” via “livesIn” edges]
g.V().has(“city”, “New York”).both(“livesIn”).dedup().count()
MATCH (c {city: ‘New York’})-[:livesIn]-() RETURN count(DISTINCT c) - 頂点「Alice」から、both(“knows”)で隣接した中で、さらにout(“created”)エッジで “SoftwareX” を持つものをフィルタする [From vertex “Alice”, filter adjacent vertices connected via “knows” edges that have an outgoing “created” edge to “SoftwareX”]
g.V().has(“name”, “Alice”).both(“knows”).where(out(“created”).has(“name”, “SoftwareX”))
MATCH (a {name: ‘Alice’})-[:knows]-(b) WHERE (b)-[:created]->(:software {name: ‘SoftwareX’}) RETURN b - 頂点「Alice」と、会社「TechCorp」に所属する頂点を結合してペアとして選ぶ [Pair vertex “Alice” with vertices belonging to the company “TechCorp”]
g.V().has(“name”, “Alice”).as(“a”).V().has(“company”, “name”, “TechCorp”).in(“worksAt”).as(“b”).select(“a”, “b”)
MATCH (a {name: ‘Alice’}), (b)-[:worksAt]->(c {name: ‘TechCorp’}) RETURN a, b - 頂点「Alice」から、その隣接頂点の「city」プロパティを抽出し、重複を除いて返す [Return distinct city properties of adjacent vertices of vertex “Alice”]
g.V().has(“name”, “Alice”).out(“knows”).values(“city”).dedup()
MATCH (a {name: ‘Alice’})-[:knows]->(b) RETURN DISTINCT b.city - 頂点「Alice」から、out(“likes”)エッジを辿り、「type」が “music” の頂点に到達するパスを取得する [Return paths from vertex “Alice” to vertices with type “music” via out(“likes”) edges]
g.V().has(“name”, “Alice”).repeat(out(“likes”)).until(has(“type”, “music”)).path()
MATCH path = (a {name: ‘Alice’})-[:likes*]->(b) WHERE b.type = ‘music’ RETURN path - 頂点「Alice」から、both()エッジを辿りながら、特定条件(visited=true)をemitしてパスを取得する [Return paths from vertex “Alice” to vertices with visited=true via both() edges]
g.V().has(“name”, “Alice”).repeat(both()).emit(has(“visited”, true)).path()
MATCH path = (a {name: ‘Alice’})-[:knows*]->(b) WHERE any(node IN nodes(path) WHERE node.visited = true) RETURN path
【側面出力(sideEffect)とデバッグ】 [SideEffect and Debugging]
- 頂点「Alice」から両隣接頂点を取得し、各頂点をsideEffectでログ出力する [Retrieve vertices adjacent to “Alice” and log each vertex using sideEffect]
g.V().has(“name”, “Alice”).both().sideEffect{ println it }
MATCH (a {name: ‘Alice’})–(b) WITH b CALL apoc.util.print(b) RETURN b
【withSideEffectの利用例】 [Examples of withSideEffect]
- withSideEffectで変数「x」に頂点IDを格納しながら、Aliceから出発する [Use withSideEffect to store vertex IDs in a variable “x” while starting from “Alice”]
g.withSideEffect(“x”, []).V().has(“name”, “Alice”).sideEffect{ it.sideEffects[“x”] << it.id() }
WITH [] AS x MATCH (a {name: ‘Alice’}) WITH a, x + id(a) AS x RETURN x
【グルーピング応用例】[Examples of Grouping]
- 頂点「tag」が “urgent” のものを、担当者(assignee)でグループ化し、その件数を集計する [Group vertices with the “urgent” tag by their assignee and count the number of vertices per assignee]
g.V().has(“tag”, “urgent”).group().by(“assignee”).by(count())
MATCH (n {tag: ‘urgent’}) RETURN n.assignee AS assignee, count(n) AS count - 頂点「Alice」から、knowsとworksAtの隣接頂点をunionで取得し、グループカウントする [Group vertices adjacent to “Alice” by their type and count the number of vertices per type]
g.V().has(“name”, “Alice”).union(out(“knows”), out(“worksAt”)).dedup().groupCount()
MATCH (a {name: ‘Alice’})-[:knows|worksAt]->(b) WITH DISTINCT b RETURN b, count(b) AS count
【foldとcoalesceの組み合わせ】 [Combination of fold and coalesce]
- 両方向の “knows” エッジを fold でまとめ、存在しなければ定数を返す [Use fold to collect both “knows” edges and return a constant if no edges exist]
g.V().has(“name”, “Alice”).bothE(“knows”).fold().coalesce(unfold().order().by(“since”, asc).limit(1),constant(“No knows edges”))
MATCH (a {name: ‘Alice’})-[e:knows]-() WITH collect(e) AS edges RETURN CASE WHEN size(edges) > 0 THEN head([edge IN edges | edge ORDER BY edge.since ASC LIMIT 1]) ELSE “No knows edges” END AS result - 頂点「Alice」の両方向すべてのエッジを取得し、そのエッジの “weight” プロパティの平均を算出する [Retrieve all edges connected to “Alice” in both directions and calculate the average of the “weight” property]
g.V().has(“name”, “Alice”).bothE().values(“weight”).mean()
MATCH (a {name: ‘Alice’})-[e]-() RETURN avg(e.weight) AS meanWeight - 頂点「Alice」の bothE で取得したすべてのエッジをグルーピングし、エッジラベルごとに件数をカウントする [Group all edges connected to “Alice” in both directions by their label and count the number of edges per label]
g.V().has(“name”, “Alice”).bothE().group().by(label).by(count())
MATCH (a {name: ‘Alice’})-[e]-() RETURN type(e) AS label, count(e) AS count