기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.
Neptune의 OpenCypher에서 실행되도록 Cypher 쿼리를 재작성
openCypher는 속성 그래프용 선언적 쿼리 언어로, Neo4j에서 처음 개발한 후 2015년에 오픈 소스로 제공되었으며, Apache 2 오픈 소스 라이선스에 따라 openCypher 프로젝트
이 구문은 Cypher 쿼리 언어 참조 버전 9
openCypher에는 Cypher 쿼리 언어의 일부 구문 및 기능이 포함되어 있으므로 일부 마이그레이션 시나리오에서는 OpenCypher 호환 형식으로 쿼리를 다시 작성하거나 원하는 기능을 구현하기 위한 대체 방법을 검토해야 합니다.
이 섹션에는 일반적인 차이점을 처리하기 위한 권장 사항이 포함되어 있지만 모든 내용을 모두 포함하는 것은 아닙니다. 이러한 재작성을 사용하는 모든 애플리케이션을 철저하게 테스트하여 결과가 예상과 일치하는지 확인해야 합니다.
None
, All
, 및 Any
술어 함수 재작성
이러한 함수는 openCypher 사양에 포함되지 않습니다. openCypher에서는 목록 포괄을 사용하여 유사한 결과를 얻을 수 있습니다.
예를 들어, Start
노드에서 노드로 이동하는 모든 경로를 찾지만 D
의 클래스 속성이 다음과 같은 End
노드를 통과하는 여정은 허용되지 않습니다.
# Neo4J Cypher code match p=(a:Start)-[:HOP*1..]->(z:End) where none(node IN nodes(p) where node.class ='D') return p # Neptune openCypher code match p=(a:Start)-[:HOP*1..]->(z:End) where size([node IN nodes(p) where node.class = 'D']) = 0 return p
이 결과를 목록 이해로 얻을 수 있습니다.
all => size(list_comprehension(list)) = size(list) any => size(list_comprehension(list)) >= 1 none => size(list_comprehension(list)) = 0
OpenCypher에서 Cypher reduce()
함수를 재작성하는 방법
reduce()
함수는 openCypher 사양에 포함되지 않습니다. 목록 내 요소에서 데이터 집계를 만드는 데 주로 사용됩니다. 대부분의 경우 목록 포괄과 UNWIND
절을 함께 사용하여 비슷한 결과를 얻을 수 있습니다.
예를 들어 다음 Cypher 쿼리는 앵커리지(ANC)와 오스틴(AUS) 사이에 1~3개의 정류장이 있는 경로의 모든 공항을 찾아 각 경로의 총 거리를 반환합니다.
MATCH p=(a:airport {code: 'ANC'})-[r:route*1..3]->(z:airport {code: 'AUS'}) RETURN p, reduce(totalDist=0, r in relationships(p) | totalDist + r.dist) AS totalDist ORDER BY totalDist LIMIT 5
다음과 같이 Neptune용 openCypher에서 동일한 쿼리를 작성할 수 있습니다.
MATCH p=(a:airport {code: 'ANC'})-[r:route*1..3]->(z:airport {code: 'AUS'}) UNWIND [i in relationships(p) | i.dist] AS di RETURN p, sum(di) AS totalDist ORDER BY totalDist LIMIT 5
openCypher의 Cypher FOREACH 절 재작성
FOREACH 절은 openCypher 사양에 포함되지 않습니다. 쿼리 도중에 데이터를 업데이트하는 데 주로 사용되며, 대개 경로 내의 집계 또는 요소에서 데이터를 업데이트하는 데 사용됩니다.
경로 예로 앵커리지(ANC)와 오스틴(AUS) 사이에 정거장이 두 곳 이하인 경로에 있는 모든 공항을 찾아 각 공항에 방문 숙소를 설정합니다.
# Neo4J Example MATCH p=(:airport {code: 'ANC'})-[*1..2]->({code: 'AUS'}) FOREACH (n IN nodes(p) | SET n.visited = true) # Neptune openCypher MATCH p=(:airport {code: 'ANC'})-[*1..2]->({code: 'AUS'}) WITH nodes(p) as airports UNWIND airports as a SET a.visited=true
또 다른 예:
# Neo4J Example MATCH p=(start)-[*]->(finish) WHERE start.name = 'A' AND finish.name = 'D' FOREACH (n IN nodes(p) | SET n.marked = true) # Neptune openCypher MATCH p=(start)-[*]->(finish) WHERE start.name = 'A' AND finish.name = 'D' UNWIND nodes(p) AS n SET n.marked = true
Neptune에서 Neo4j APOC 프로시저 재작성
아래 예제는 OpenCypher를 사용하여 가장 일반적으로 사용되는 APOC 프로시저
apoc.export
프로시저 재작성
Neptune은 neptune-export
apoc.schema
프로시저 재작성
Neptune에는 명시적으로 정의된 스키마, 인덱스 또는 제약 조건이 없으므로 더 이상 많은 apoc.schema
프로시저가 필요하지 않습니다. 예:
apoc.schema.assert
apoc.schema.node.constraintExists
apoc.schema.node.indexExists
,apoc.schema.relationship.constraintExists
apoc.schema.relationship.indexExists
apoc.schema.nodes
apoc.schema.relationships
Neptune OpenCypher는 아래 그림과 같이 프로시저가 수행하는 것과 유사한 값 검색을 지원하지만 큰 그래프에서는 그래프의 많은 부분을 스캔하여 답을 반환해야 하므로 성능 문제가 발생할 수 있습니다.
# openCypher replacement for apoc.schema.properties.distinct MATCH (n:airport) RETURN DISTINCT n.runways
# openCypher replacement for apoc.schema.properties.distinctCount MATCH (n:airport) RETURN DISTINCT n.runways, count(n.runways)
apoc.do
프로시저의 대안
이러한 프로시저는 다른 openCypher 절을 사용하여 쉽게 구현할 수 있는 조건부 쿼리 실행을 제공하는 데 사용됩니다. Neptune에서는 최소한 두 가지 방법으로 유사한 동작을 수행할 수 있습니다.
한 가지 방법은 OpenCypher의 목록 이해 기능을
UNWIND
절과 결합하는 것입니다.또 다른 방법은 그렘린에서 choose() 및 coalesce() 단계를 사용하는 것입니다.
이러한 접근 방식의 예는 다음과 같습니다.
apoc.do.when의 대안
# Neo4J Example MATCH (n:airport {region: 'US-AK'}) CALL apoc.do.when( n.runways>=3, 'SET n.is_large_airport=true RETURN n', 'SET n.is_large_airport=false RETURN n', {n:n} ) YIELD value WITH collect(value.n) as airports RETURN size([a in airports where a.is_large_airport]) as large_airport_count, size([a in airports where NOT a.is_large_airport]) as small_airport_count # Neptune openCypher MATCH (n:airport {region: 'US-AK'}) WITH n.region as region, collect(n) as airports WITH [a IN airports where a.runways >= 3] as large_airports, [a IN airports where a.runways < 3] as small_airports, airports UNWIND large_airports as la SET la.is_large_airport=true WITH DISTINCT small_airports, airports UNWIND small_airports as la SET la.small_airports=true WITH DISTINCT airports RETURN size([a in airports where a.is_large_airport]) as large_airport_count, size([a in airports where NOT a.is_large_airport]) as small_airport_count #Neptune Gremlin using choose() g.V(). has('airport', 'region', 'US-AK'). choose( values('runways').is(lt(3)), property(single, 'is_large_airport', false), property(single, 'is_large_airport', true)). fold(). project('large_airport_count', 'small_airport_count'). by(unfold().has('is_large_airport', true).count()). by(unfold().has('is_large_airport', false).count()) #Neptune Gremlin using coalesce() g.V(). has('airport', 'region', 'US-AK'). coalesce( where(values('runways').is(lt(3))). property(single, 'is_large_airport', false), property(single, 'is_large_airport', true)). fold(). project('large_airport_count', 'small_airport_count'). by(unfold().has('is_large_airport', true).count()). by(unfold().has('is_large_airport', false).count())
apoc.do.case의 대안
# Neo4J Example MATCH (n:airport {region: 'US-AK'}) CALL apoc.case([ n.runways=1, 'RETURN "Has one runway" as b', n.runways=2, 'RETURN "Has two runways" as b' ], 'RETURN "Has more than 2 runways" as b' ) YIELD value RETURN {type: value.b,airport: n} # Neptune openCypher MATCH (n:airport {region: 'US-AK'}) WITH n.region as region, collect(n) as airports WITH [a IN airports where a.runways =1] as single_runway, [a IN airports where a.runways =2] as double_runway, [a IN airports where a.runways >2] as many_runway UNWIND single_runway as sr WITH {type: "Has one runway",airport: sr} as res, double_runway, many_runway WITH DISTINCT double_runway as double_runway, collect(res) as res, many_runway UNWIND double_runway as dr WITH {type: "Has two runways",airport: dr} as two_runways, res, many_runway WITH collect(two_runways)+res as res, many_runway UNWIND many_runway as mr WITH {type: "Has more than 2 runways",airport: mr} as res2, res, many_runway WITH collect(res2)+res as res UNWIND res as r RETURN r #Neptune Gremlin using choose() g.V(). has('airport', 'region', 'US-AK'). project('type', 'airport'). by( choose(values('runways')). option(1, constant("Has one runway")). option(2, constant("Has two runways")). option(none, constant("Has more than 2 runways"))). by(elementMap()) #Neptune Gremlin using coalesce() g.V(). has('airport', 'region', 'US-AK'). project('type', 'airport'). by( coalesce( has('runways', 1).constant("Has one runway"), has('runways', 2).constant("Has two runways"), constant("Has more than 2 runways"))). by(elementMap())
목록 기반 속성의 대안
Neptune은 현재 목록 기반 속성 저장을 지원하지 않습니다. 하지만 목록 값을 쉼표로 구분된 문자열로 저장한 다음 join()
및 split()
함수를 사용하여 목록 속성을 구성 및 분해하면 비슷한 결과를 얻을 수 있습니다.
예를 들어 태그 목록을 속성으로 저장하려는 경우 쉼표로 구분된 속성을 검색한 다음 split()
및 join()
함수를 ‘List Compremension’과 함께 사용하여 유사한 결과를 얻는 방법을 보여주는 재작성 예제를 사용할 수 있습니다.
# Neo4j Example (In this example, tags is a durable list of string. MATCH (person:person {name: "TeeMan"}) WITH person, [tag in person.tags WHERE NOT (tag IN ['test1', 'test2', 'test3'])] AS newTags SET person.tags = newTags RETURN person # Neptune openCypher MATCH (person:person {name: "TeeMan"}) WITH person, [tag in split(person.tags, ',') WHERE NOT (tag IN ['test1', 'test2', 'test3'])] AS newTags SET person.tags = join(newTags,',') RETURN person