Filtering Queries

pDestiny·2022년 9월 3일
0

Network Science

목록 보기
5/10
post-thumbnail

이 자료는 neo4j의 GraphAcademy의 Intermediate Cypher Queries 강의의 내용임을 밝혀 둡니다. 사용된 데이터는 주어지는 sandbox에서 사용 가능합니다.

Filtering Queries

Basic Cypher Queries

Horror Movie Directors
Write and execute a query to return the names of directors of horror movies released in the year 2000. Use the year property of the Movie node to do the comparison as well as the name of "Horror" for the Genre node.
Once you executed, enter the number of rows returned below and click Check

그래프로부터 호러영화를 찍은 디렉터의 수를 반환하라는 Cypher Query를 작성하라는 문제이다. 디렉터(:Director)는 영화(:Movie)를 디렉팅 하고[:Directed] 영화는 장르(:Genre)를 가지고 있음으로[:IN_GENRE] match query 는 다음과 같다.

MATCH (d:Director)-[:DIRECTED]->(m:Movie)-[:IN_GENRE]->(g:Genre)

그런데 조건에 2000년에 나왔고, Horror 영화여야 함을 where 조건을 넣고 디렉터의 숫자를 얻어야 하니 count 내장함수를 이용하여 반환한다.

MATCH (d:Director)-[:DIRECTED]->(m:Movie)-[:IN_GENRE]->(g:Genre)
WHERE m.year = 2000 AND g.name = "Horror"
RETURN count(d) # 23

그러면 23이 나오게 된다.

Querying for Null Values

neo4j의 cypher는 null 값을 처리하는게 생각보다 까다롭다. 이상한 값들이 나오기 때문이다. udemy 의 neo4j 기초 코스에서도 null 에 대해 설명하고 있는데 아래와 같다.

  1. 존재하지 않는 property를 반환할때 null 값을 반환한다.
MATCH (n) RETURN n.prop_does_not_exist ; # null값을 반환
  1. OPTIONAL MATCH를 사용하여 관계를 가져오려고 할 때, 아래와 같은 관계를 가져오려고 할때, OPTIONAL MATCH 구문을 사용할 경우 n을 모두 가져오되, OPTIONAL MATCH와 일치하지 않는 관계가 있더라도 가져오는데, 이 때, NULL 값을 반환하게 된다.
MATCH (n)
OPTIONAL MATCH (n)->[rel:A_REL]->(:LABEL_B)
RETURN n, rel
  1. LIST에서 존재하지 않는 index의 데이터를 가져오려고 할 경우 NULL을 반환한다. 즉 에러를 발생시키지 않고 조용히 NULL값을 반환한다.
WITH [1, 2, 3] AS myList
RETURN myList[3] # NULL
  1. Boolean Logic에서 undefined를 쓰면, 예를 들면 아래와 같이 false OR NULL에서 OR 로직에 따라 false 다음 NULL을 판단해야 해야 하는데, NULL은 false가 아니고, undefined라는 의미를 가짐으로, false가 아니라 undefined null이 반환된다.
WITH (false OR NULL) AS result
RETURN result # null(undefined)

마찬가지로 (true and null)에서도 결과는 null이 나온다.

WITH (true AND NULL) AS result
RETURN result # null(undefined)
  1. IN 키워드에서 특히 null은 이상하게 작동하는데, 리스트에 null 값을 넣고, null이 리스트에 있는지 판단하려고 하면 null을 반환한다.
WITH (null in [null]) AS result RETURN result; # null

null이 리스트에 존재하지 않을때 null이 리스트에 있는지를 판단하려고 할때도 결과는 false가 아니라 null 이 나온다. 즉, null은 리스트에 있는지 없는지 판단할 수 없다.

WITH (null in [1,2,3]) AS result RETURN result; # null

이런 Cypyher의 이상한 undefined라는 null의 개념때문에 null을 체크하기 위해서는 직접 IS NULL statement를 사용해야 한다.

equal operator를 사용하면 이상한 결과를 가져온다. 왜냐하면 null은 계산의 대상이 아니기 때문이다.

WITH (null = null) AS result RETURN result # NULL
WITH (null <> null) AS result RETURN result # NULL
WITH (null IS NULL) AS result RETURN result # TRUE
WITH (null IS NOT null) AS result RETURN result # TRUE

강의에서는 IS NULL, IS NOT NULL 을 NULL Gotcha 라고 표한한다.

  1. 리스트에 null을 추가하면 결과는 null이다. 하려면 [null]을 추가해야 한다.
WITH ([1, 2, 3] + null) AS result RETURN result # null

이렇게 하는 대신에 아래와 같은 쿼리를 날린다.

WITH ([1, 2, 3] + [null]) AS result RETURN result # [1,2,3,null]

Question

Write and execute a query to return all Movie nodes in the graph that do not have a tmdbId property. How many Movie nodes are returned?

movie에서 tmdbId property가 없는 movie의 숫자를 세라는 문제이다. 위에서 언급한 1번 경우, property가 존재하지 않는 경우 null값을 반환하는 케이스임으로 단순하게 null gotcha를 이용해 문제를 해결 할 수 있다.

MATCH (m:Movie)
WHERE m.tmdbId IS NULL
RETURN count(m) # 4

Checking for NULL Values

Write and execute a query to return the titles of all movies that do not have a poster. Once you executed, enter the number of rows returned below and click Check

마찬가지로 존재하지 않는 property를 가지고 있는 노드의 수를 세는 문제이다.

MATCH (m:Movie)
WHERE m.poster IS NULL
RETURN count(m.title) # 149

Range Query

Using the sandbox on the right, write and execute a query to return people born in the 1950’s (1950 - 1959) that are both Actors and Directors. How many Person nodes are returned?

1950년과 1959년 사이에 태어난 Actor이자 Director인 사람의 수를 가져오라는 쿼리를 작성해야 한다. 아래와 같이 쿼리할 수 있다.

MATCH (p:Person:Actor:Director)
WHERE 1950<= p.born.year <= 1959
RETURN count(p)

Testing List Inclusion

Write and execute a query to return people who both acted in and directed a movie released in the German language.
How many unique Person node names are returned? (There will be duplicates that you should not count)

Movie에서 language property가 있으니, 독일어를 쓰는 영화에 출연하고 디렉팅했던 사람을 중복 없이 찾으라는 쿼리이다. 아래와 같이 쿼리할 수 있다.

MATCH (p:Person)-[:ACTED_IN]->(m:Movie)
MATCH (p)-[:DIRECTED]->(m)
WHERE "German" in m.languages
WITH DISTINCT p.name AS pName
RETURN count(pName) # 3

solution은 아래와 같다. 아래 버전은 distinct predicate를 쓰지 않아 중복된 이름이 나온다. 하지만 match 구문이 훨씬 간단하다.

MATCH (p:Director)-[:DIRECTED]->(m:Movie)<-[:ACTED_IN]-(p)
WHERE "German" IN m.languages
return p.name, labels(p), m.title

Testing Strings

Check movie titles
Write and execute a query to return all Movie titles in the graph that have a title that begins with "Life is". There may be titles that do not adhere to capitalization as such so you must ensure that all titles will match. That is, it will retrieve any case of the string, such as "Life is", "LIFE IS", "life is", "Life Is". How many Movie nodes are returned?

Query로 title을 찾을 때, Life is 로 시작되는 title을 찾되, case 에 관계없이 찾아라는 것이다.

MATCH (m:Movie)
WHERE toLower(m.title) STARTS WITH 'life is'
RETURN m.title # 총 4개

Using the CONTAINS Predicate

CONTAINS predicate를 사용하면, starts with 혹은 ends with과 달리 중간에 있는 값도 찾아 낼 수 있다.

Write and execute a query to return the name of the person, their role, and the movie title where the role played by the actors or director had a value that included 'dog' (case-insensitive)? That is, the role could contain "Dog", "dog", or even "DOG". Once you executed, enter the number of rows returned below and click Check

Person - role \rightarrow movie 로 이어지는 연결 관계를 찾고, role에서 dog를 가지고 있는 role의 개수를 반환하라는 문제이다.

MATCH (:Person)-[rel]->(m:Movie)
WHERE toLower(rel.role) CONTAINS 'dog'
RETURN count(rel) # 27개

Query Patterns and Peformance

write and execute a query to return the titles of all movies that Rob Reiner directed, but did not act in. How many Movie titles are returned?

Rob Reiner가 감독하되, 출연하지 않은 영화의 수를 EXISTS 키워드를 이용해 표현 할 수있다.

match (p:Person)-[:DIRECTED]->(m:Movie)
where p.name = 'Rob Reiner' AND NOT EXISTS {(p)-[:ACTED_IN]->(m)}
return count(m) # 14개

PROFILE 명령어를 사용하면 그 쿼리의 efficiency를 알 수 있다. 쿼리의 각 스탭에서 몇개의 데이터를 가져오는지 볼 수 있기 때문이다. 해당 문제는 쿼리가 각 스탭에서 전체 몇개의 데이터를 가져왔는지를 구하라는 문제이다.

위의 그림은 PROFILE predicate로 쿼리를 작성하였을 때 출력되는 그림이다.
db hits의 총 합은 2 + 43 + 40 + 404 + 20 = 509 이다.

Multiple MATCH Clauses

MATCH (m:Movie) WHERE m.title = "Kiss Me Deadly"
MATCH (m)-[:IN_GENRE]->(g:Genre)<-[:IN_GENRE]-(rec:Movie)
MATCH (m)<-[:ACTED_IN]-(a:Actor)-[:ACTED_IN]->(rec)
RETURN rec.title, a.name

위의 쿼리는 3가지 작업을 수행한다.

  1. "Kiss Me Deadly" 영화를 찾는다.

  2. "Kiss Me Deadly" 와 동일한 장르의 영화를 찾는다.

  3. "Kiss Me Deadly"와 동일한 장르의 영화에 출연한 배우를 찾는다.

이 결과는 딱 1 행의 결과만을 가져온다.

OPTIONAL MATCH를 사용하면 2번의 모든 결과를 가져오 되, 3번도 포함시키는 결과를 가져 올 수있다. 대신, 2번과 3번 모두 매칭되는 결과가 아닌 경우 null 값으로 배우는 처리된다.

MATCH (m:Movie) WHERE m.title = "Kiss Me Deadly"
MATCH (m)-[:IN_GENRE]->(g:Genre)<-[:IN_GENRE]-(rec:Movie)
OPTIONAL MATCH (m)<-[:ACTED_IN]-(a:Actor)-[:ACTED_IN]->(rec)
RETURN rec.title, a.name

genre가 Film-Noir이되, 평가가 됐든 안됐든 사용자를 가져오는 쿼리로 바꾸기 위해서는 두번째 MATCH 구문 앞에 OPTIONAL을 쓰면 된다.

MATCH (m:Movie)-[:IN_GENRE]->(g:Genre)
WHERE g.name = 'Film-Noir'
OPTIONAL MATCH (m)<-[:RATED]-(u:User)
RETURN m.title, u.name
profile
Bioinformatician

0개의 댓글