기타/프로그래밍

[그래프 데이터베이스][무작정해보기] [12/30] WHERE 를 활용한 쿼리

코드아키택트 2021. 1. 28. 19:29
반응형

SQL과 비슷하게 WHERE를 활용해서 원하는 노드를 Query할 수 있다. 

 

기본 질의문 구성은 다음과 같다

MATCH (n)
WHERE n.property = what_you_want
RETURN n.other_property

 위의 질의문은 오직 노드에 대한 결과값을 처리하게 된다. 노드의 어떤 속성이 WHERE안의 조건과 맞는 노드를 RETURN하는 방식이다. 그냥 노드를 RETURN하게 해도 되고, 원하는 Property만 꺼낼 수도 있다. 

 

 

 

 특정 범위에 맞는 데이터 Query하기

MATCH (p:Person)-[:ACTED_IN]->(m:Movie)
WHERE m.released >= 2003 AND m.released <= 2004
RETURN p.name, m.title, m.released

 위를 보면 다음과 같은 구조를 가지고 있다. 우선 MATCH 절에 p와 m변수를 할당했으며, 이 둘은 각각 Person,Movie라는 라벨을 가지고 있다. 둘 사이의 관계는 ACTED_IN으로 연결되어 있다. 말로 풀어서 설명해보자면 " 어떤영화에서 연기한 어떤 사람. 어떤 사람 노드는 p에 할당하고, 어떤 영화 노드는 m에 할당한다."
 WHERE절은 특정 조건을 정의한다. 예제에 활용되는 Movie노드의 경우, released라는 속성을 가지고 있다. 개봉년도 또는 발행년도 정도로 해석하면 될 것 같다. WHERE절은 AND를 활용해서 2003년 이상, 2004년 이하 중 발행된 영화라는 조건을 걸었다고 생각하면 된다.

 마지막의 RETURN절에선 이미 WHERE 절을 통해 원하는 노드들이 Queyr되었기 때문에 그중에서 필요한 Property만 RETURN하도록 한것을 볼 수 있다. Neo4j를 사용하면서 보니, 위와 같이 node.property식으로 질의문을 쓰게 되면 노드자체는 RETURN 되지 않고 SQL처럼 해당하는 Property만 RETURN 된다. 시각적으로 노드를 보고 싶다면 점(.)뒤의 부분을 생략하면 된다.

 위의 사이퍼 질의문을 다른 방식으로 쓸 수 있다.

MATCH (p:Person)-[:ACTED_IN]->(m:Movie)
WHERE 2003 <= m.released <= 2004
RETURN p.name, m.title, m.released

즉, AND를 없애고 m.released자체를 두 수 사이에 끼워넣은 방식이다. 튜토리얼 중간중간 같은 결과에대해 여러 방식이 나오는데, 잘 알아둬야 겠다.

 

 

 

속성의 존재여부에 따라 Query하기

 SQL이랑은 다르게 같은 라벨을 가진 노드 또는 같은 관계 타입이라고 해도 같은 속성값을 꼭 지니고 있는 것은아니다. 가령 예제의 영화 데이터로 예를 든다면, tagline(한줄정리 정도?)이라는 속성은 모든 영화가 가지고 있는 것은 아니다.

4번째의 태그라인을 보면 없는 것을 확인 할 수 있다.

 여기 예제에선 태그라인이 있으며, 'Jack Nicholson'이 연기한 영화들만 뽑아내는 것을 보여준다.

MATCH (p:Person)-[:ACTED_IN]->(m:Movie)
WHERE p.name='Jack Nicholson' AND exists(m.tagline)
RETURN m.title, m.tagline

Something's Gotta Give가 없어졌다.

 

 

 

문자(String) 포함 여부로 Query하기

 문자 포함 부는 STARTS WITH, ENDS WITH, CONTAINS를 사용할 수 있다. 각각 말 그대로, 특정 문자로 시작하는 경우, 특정 문자로 끝나는 경우, 특정 문자를 포함하는 경우로 나눌 수 있다. 주의할 것은 대소문자를 구분한다는 것이다.

 예를 들어, 'Michael'이라는 이름으로 시작하는 모든 배우를 찾기위해선 다음과 같이 쓸 수 있다.

MATCH (p:Person)-[:ACTED_IN]->()
WHERE p.name STARTS WITH 'Michael'
RETURN p.name

 대소문자 구분을 피하고 싶다면, 다음과 같은 방법을 사용할 수도 있다. 원리는 모든것을 소문자로 바꾼 후, 소문자 'michael'과 비교하는 것이다.

MATCH (p:Person)-[:ACTED_IN]->()
WHERE toLower(p.name) STARTS WITH 'michael'
RETURN p.name

 실행해봤을때, 위와 동일한 결과가 나왔다.

 

별(*)을 활용한 문자 찾기

 Asterisk라고들 부르는 것 같다. 튜토리얼에 나와있어서 소개하지만 이해는 잘 하지 못했다. START WITH와는 동일하게 사용할 수 있었지만, END WITH나 CONTAINS와 같은 방식으로는 사용 할 수 없었다.

MATCH (p:Person)
WHERE p.name =~'Tom.*'
RETURN p.name

Tom으로 시작하는 사람들의 이름을 받아온 경우.

 

 

 

패턴 활용하여 QUERY하기

 exists와 NOT을 활용해서 다양한 시나리오에서 원하는 값을 찾아낸다

 

대본은 썼지만, 감독하지 않은경우

MATCH (p:Person)-[:WROTE]->(m:Movie)
WHERE NOT exists( (p)-[:DIRECTED]->(m) )
RETURN p, m

 MATCH 부분에서 어떤 영화를 쓴 사람을 Query하도록 되어있다. 하지만, p에서 m노드로 WROTE이 외의 관계도 존재할 수 있다. 

NOT exists를 사용하지 않은 경우

직접 실행해보니, 어떤 영화를 WROTE한 사람 중에선 PRODUCED, ACTED_IN 등 다양한 행위를 한 사람들이 있었다. 

NOT exists사용 후

 하지만  NOT exists를 사용하면, 어떤 영화를 WROTE했으면서, DIRECTED(감독)한 경우는 나오지 않았다.

 

 

 

IN을 활용해서 list 값과 비교하여 QUERY하기

 하나의 범주에 대해 IN을 활용하면 각각 비교할 수 있었다. 예를 들면, 특정 년도에 태어난 사람들을 찾아내고 싶다면 다음과 같이 쓸 수 있을 것이다.

MATCH (p:Person)
WHERE p.born=1965 OR p.born=1970
RETURN p.name as name, p.born as yearBorn

 1965년 또는 1970년에 태어난 사람들을 찾아볼 수 있다. 하지만, 경우가 여러개가 될 경우 WHERE절에 p.born을 여러번 써야하고, 오타가 많아지며 데이터를 제대로 추출하지 못할 확률이 크다. 이때 IN을 사용 할 수 있다.

MATCH (p:Person)
WHERE p.born IN [1965, 1970]
RETURN p.name as name, p.born as yearBorn

 위와같이 쓴다면, p.born은 한번만 쓰면되고, IN뒤에 있는 리스트에 대해 각각 비교해주니 좀더 편리한 방법이라고 할 수 있다.

 

 

활용해보기

 

 예제에서 한 인물에 대한 :ACTED_IN은 role이라는 속성을 가진다. 그 말은, 한 배우가 출연한 영화에 대한 역할이름이 각각 담겨있다는 뜻이다. 이를 한데 모으면 list가 된다. 아래 예제는 Neo라는 배역으로 The Matrix에 출연한 영화배우를 찾는 문장을 보여준다(이미 답은 예상할 수 있지만)

MATCH (p:Person)-[r:ACTED_IN]->(m:Movie)
WHERE  'Neo' IN r.roles AND m.title='The Matrix'
RETURN p.name

 

이로서 WHERE부분 튜토리얼 부분이 끝났다. 

 

 

 

끝마치며

 오늘 개인적으로 데이터베이스에 무작정 노드를 넣어보았다. 데이터를 넣고, 그 다음 관계를 만드는 과정에서 문자들이 틀리지 않게 잘 넣어야 겠다는 생각이 많이 들었고, 하나하나 손으로 넣자니 조금 번거롭기도 했다. 다른 예제중에 CSV등을 통해 넣는 예제들이 있던데 그런것들을 활용하거나, 작은 Application을 만들어서 입력작업을 수월하게 해가며 공부를 진행해보면 좋을 것 같다. 몇몇 원 예제들은 생략하였으니 필요하신분들은 링크를 통해 해보시는것을 추천한다.

 

 

 

참고자료


neo4j.com/graphacademy/training-querying-40/02-querying40-using-where-to-filter-queries/

반응형