728x90
반응형
  • Cypher & GQL

소개

The Neo4j 영화 앱 템플릿은 다음 단계를 위한 사용하기 쉬운 기반을 제공해요. , Node.js 또는 React.js를 사용하여 프로젝트를 진행하거나 실험해 볼 수 있죠. 이 문서에서는 로그인하여 웹 앱의 데이터와 상호 작용할 수 있는 `Users`를 생성하는 과정을 안내합니다.

Neo4j 영화 앱 템플릿에서, 이러한 `Users`는 로그인 및 로그아웃하고, 영화를 평가하고, 영화 추천을 받을 수 있어요.

사용자 모델

스스로 생성하고 앱으로 인증하는 것 외에도 `Users` (파란색)는 `Movies` (노란색)를 평가할 수 있어요. `:RATED` 관계는 아래 그래프 데이터 모델에 설명되어 있습니다.

User 속성
    • password: 사용자가 선택한 비밀번호의 해시된 버전
    • api_key: 사용자가 요청을 인증하는 데 사용하는 사용자의 API 키
    • id: 사용자의 고유 ID
    • username: 사용자가 선택한 사용자 이름
:RATED 속성

rating: 1과 5 사이의 정수 등급이에요. 5는 를, 1은 를 의미하죠.

사용자는 계정을 만들 수 있어요

User가 Movie를 평가하기 전에, 사용자가 있어야겠죠? 누군가가 계정에 가입해야 해요. 가입하면 데이터베이스에 User Label이 붙은 Node가 생성되고, 로그인 및 세션 유지에 필요한 속성들이 함께 저장돼요.

그림 1. web/src/pages/Signup.jsx

등록 엔드포인트는 /api/v0/register에 있어요. 사용자가 "계정 만들기" 양식을 작성하고 "계정 만들기"를 누르면 앱은 등록 엔드포인트에 요청을 보내죠.

API가 실행 중이라고 가정하면, 다음 대화형 문서를 사용하여 요청을 테스트할 수 있어요: 3000/docs/, 또는 cURL을 사용해도 되고요.

사용 사례: 새 사용자 생성

 
curl -X POST 
--header 'Content-Type: application/json' 
--header 'Accept: application/json' 
-d '{ "username": "Mary Jane", "password": "SuperPassword"}' 'https://localhost:3000/api/v0/register'
 
{
   "id":"e1e157a2-1fb5-416a-b819-eb75c480dfc6",
   "username":"Mary333 Jane",
   "avatar":{
      "full_size":"https://www.gravatar.com/avatar/b2a02b21db2222c472fc23ff78804687?d=retro"
   }
}

사용 사례: 새 사용자를 생성하려고 시도했지만 username이 이미 사용 중이에요.

 
curl -X POST 
--header 'Content-Type: application/json' 
--header 'Accept: application/json' 
-d '{ "username": "Mary Jane", "password": "SuperPassword"}' 'https://localhost:3000/api/v0/register'
 
{
   "username":"username already in use"
}

사용자 등록 로직은 다음에서 구현됩니다./api/models/users.js. JavaScript 코드는 다음과 같아요.

var register = function(session, username, password) {
    return session.run('MATCH (user:User {username: {username}}) RETURN user', {
            username: username
        })
        .then(results => {
            if (!_.isEmpty(results.records)) {
                throw {
                    username: 'username already in use',
                    status: 400
                }
            }
            else {
                return session.run('CREATE (user:User {id: {id}, username: {username},
                       password: {password}, api_key: {api_key}}) RETURN user', {
                    id: uuid.v4(),
                    username: username,
                    password: hashPassword(username, password),
                    api_key: randomstring.generate({
                        length: 20,
                        charset: 'hex'
                    })
                }).then(results => {
                    return new User(results.records[0].get('user'));
                })
            }
        });
};

사용자는 로그인할 수 있어요

이제 사용자가 계정을 등록할 수 있으니, 사이트에 로그인하고 세션을 시작할 수 있는 화면을 만들어볼까요?

그림 2. /web/src/pages/Login.jsx

등록 endpoint는 다음 위치에 있어요./api/v0/login. 사용자가 username과 password를 입력하고 "계정 만들기"를 누르면 앱이 로그인 endpoint에 요청을 보내죠.

API가 실행 중이라면, 다음 interactive 문서를 사용해서 요청을 테스트해볼 수 있어요.3000/docs/, 아니면 cURL을 사용해도 되고요.

사용 사례: 로그인

 
curl -X POST 
--header 'Content-Type: application/json' 
--header 'Accept: application/json' 
-d '{"username": "Mary Jane", "password": "SuperPassword"}' 'https://localhost:3000/api/v0/login'
 
{
	"token":"5a85862fb28a316ea6a1"
}

사용 사례: 잘못된 password

 
curl -X POST 
--header 'Content-Type: application/json' 
--header 'Accept: application/json' 
-d '{ "username": "Mary Jane", "password": "SuperPassword"}' 'https://localhost:3000/api/v0/register'
 
{
   "username":"username already in use"
}

사용 사례: 내 정보 보기

 
curl -X GET 
--header 'Accept: application/json' 
--header 'Authorization: Token 5a85862fb28a316ea6a1' 'https://localhost:3000/api/v0/users/me'
 
{
  "id": "94a604f7-3eab-4f28-88ab-12704c228936",
  "username": "Mary Jane",
  "avatar": {
    "full_size": "https://www.gravatar.com/avatar/c2eab5611cabda1c87463d7d24d98026?d=retro"
  }
}

구현은 /api/models/users.js에서 확인할 수 있어요:

var me = function(session, apiKey) {
    return session.run('MATCH (user:User {api_key: {api_key}}) RETURN user', {
            api_key: apiKey
        })
        .then(results => {
            if (_.isEmpty(results.records)) {
                throw {
                    message: 'invalid authorization key',
                    status: 401
                };
            }
            return new User(results.records[0].get('user'));
        });
};
var login = function(session, username, password) {
    return session.run('MATCH (user:User {username: {username}}) RETURN user', {
            username: username
        })
        .then(results => {
            if (_.isEmpty(results.records)) {
                throw {
                    username: 'username does not exist',
                    status: 400
                }
            }
            else {
                var dbUser = _.get(results.records[0].get('user'), 'properties');
                if (dbUser.password != hashPassword(username, password)) {
                    throw {
                        password: 'wrong password',
                        status: 400
                    }
                }
                return {
                    token: _.get(dbUser, 'api_key')
                };
            }
        });
};

여기 코드는 /register와 비슷할 거예요. 사용자가 username과 password를 입력하는 비슷한 폼이 있죠.

입력된 사용자 이름으로 User가 초기화돼요. 폼에 작성한 비밀번호는 :User 데이터베이스의 `Node`에서 검색된 해시된 비밀번호와 비교해서 확인하고요.

확인이 성공하면 토큰이 반환돼요. 그러면 사용자는 앱을 탐색하고, 사용자 프로필을 보고, 영화를 평가할 수 있는 인증된 페이지로 이동하게 돼요. 다음은 새로 생성된 사용자에 대한 다소 비어 있는 사용자 프로필이에요.

그림 3. /web/src/pages/Profile.jsx

사용자는 영화를 평가할 수 있어요

사용자가 로그인해서 영화를 보여주는 페이지로 가면, 영화에 별점 평가를 남기거나 이미 평가했던 영화의 별점을 수정할 수 있어요.

사용자는 자신의 프로필과 영화 상세 정보 페이지에서 이전에 평가했던 영화 목록과 평가 점수를 확인할 수 있어야 해요.

사용 사례: 영화 평가

요구 사항 (Request)
curl -X POST 
--header 'Content-Type: application/json' 
--header 'Accept: application/json' 
--header 'Authorization: Token 5a85862fb28a316ea6a1' 
-d '{"rating":4}' 'https://localhost:3000/api/v0/movies/683/rate'
응답 (Response)
{}

사용 사례: 내 모든 평가 보기

요구 사항 (Request)
curl -X GET 
--header 'Accept: application/json' 
--header 'Authorization: Token 5a85862fb28a316ea6a1' 'https://localhost:3000/api/v0/movies/rated'
응답 (Response)
[
  {
    "summary": "Six months after the events depicted in The Matrix, ...",
    "duration": 138,
    "rated": "R",
    "tagline": "Free your mind.",
    "id": 28,
    "title": "The Matrix Reloaded",
    "poster_image": "https://image.tmdb.org/t/p/w185/ezIurBz2fdUc68d98Fp9dRf5ihv.jpg",
    "my_rating": 4
  },
  {
    "summary": "Thomas A. Anderson is a man living two lives....",
    "duration": 136,
    "rated": "R",
    "tagline": "Welcome to the Real World.",
    "id": 1,
    "title": "The Matrix",
    "poster_image": "https://image.tmdb.org/t/p/w185/gynBNzwyaHKtXqlEKKLioNkjKgN.jpg",
    "my_rating": 4
  }
]

사용 사례: 특정 영화에 대한 내 평가 보기

요구 사항 (Request)
curl -X GET 
--header 'Accept: application/json' 
--header 'Authorization: Token 5a85862fb28a316ea6a1' 'https://localhost:3000/api/v0/movies/1'
응답 (Response)
{
   "summary":"Thomas A. Anderson is a man living two lives....",
   "duration":136,
   "rated":"R",
   "tagline":"Welcome to the Real World.",
   "id":1,
   "title":"The Matrix",
"poster_image":"https://image.tmdb.org/t/p/w185/gynBNzwyaHKtXqlEKKLioNkjKgN.jpg",
   "my_rating":4,
   "directors":[...],
   "genres":[...],
   "producers":[...],
   "writers":[...],
   "actors":[...],
   "related":[...],
   "keywords":[...]
}

사용자는 자신의 정보를 바탕으로 영화를 추천받을 수 있어요.

사용자가 자신의 프로필 페이지에 방문하면, 추천 영화 목록을 볼 수 있죠. 추천 엔진을 구축하는 방법은 정말 다양해요. 아래 방법들 중 하나 또는 여러 방법을 조합해서 특정 사용 사례에 딱 맞는 추천 시스템을 만들 수 있답니다.

영화 템플릿에서 추천 엔드포인트는 movies/recommended에서 찾을 수 있어요.

사용자 중심, 사용자 기반 추천

여기 사용자 중심 추천에 대한 Cypher 쿼리 예시가 있어요:

MATCH (me:User {username:'Sherman'})-[my:RATED]->(m:Movie)
MATCH (other:User)-[their:RATED]->(m)
WHERE me <> other
AND abs(my.rating - their.rating) < 2
WITH other,m
MATCH (other)-[otherRating:RATED]->(movie:Movie)
WHERE movie <> m
WITH avg(otherRating.rating) AS avgRating, movie
RETURN movie
ORDER BY avgRating desc
LIMIT 25
영화 중심, 키워드 기반 추천

최신 영화는 등급이 거의 없거나 아예 없을 수도 있어서, 애플리케이션이 사용자의 등급 기반 추천을 사용한다면 사용자에게 추천되지 않을 수 있어요.

영화에는 키워드가 있으니, 애플리케이션은 특정 영화에 대해 유사한 키워드를 가진 영화를 추천할 수 있겠죠. 이 방법은 사용자가 평가를 거의 하지 않았거나 아예 하지 않았을 때 유용해요.

예를 들어, 다음과 같은 영화에 관심 있는 방문자는 Elysium과 유사한 키워드가 포함된 영화에 관심을 가질 가능성이 높겠죠?

MATCH (m:Movie {title:'Elysium'})
MATCH (m)-[:HAS_KEYWORD]->(k:Keyword)
MATCH (movie:Movie)-[r:HAS_KEYWORD]->(k)
WHERE m <> movie
WITH movie, count(DISTINCT r) AS commonKeywords
RETURN movie
ORDER BY commonKeywords DESC
LIMIT 25
사용자 중심, 키워드 기반 추천

확고한 취향을 가진 사용자는 자신이 높게 평가한 영화와 유사한 특성을 가진 영화를 찾는 데 관심이 있을 수 있지만, 다른 사용자가 이미 영화를 평가했는지는 신경 쓰지 않을 수도 있어요. 예를 들어, Sherman은 많은 영화를 봤고 이미 본 것과 유사한 새로운 영화를 찾고 있다고 해봐요.

MATCH (u:User {username:'Sherman'})-[:RATED]->(m:Movie)
MATCH (m)-[:HAS_KEYWORD]->(k:Keyword)
MATCH (movie:Movie)-[r:HAS_KEYWORD]->(k)
WHERE m <> movie
WITH movie, count(DISTINCT r) AS commonKeywords
RETURN movie
ORDER BY commonKeywords DESC
LIMIT 25

다음 단계

    • neo4j-flask 살펴보기
    • Neo4j 영화 템플릿의 Python 버전을 살펴보세요.
Neo4j와 같은 Graph Database로 무엇을 할 수 있는지 더 자세히 알고 싶으신가요?
아래를 클릭하여 O'Reilly 도서의 무료 사본을 받고 그래프 기술의 힘을 활용하는 방법을 알아보세요.
  • curl
  • Cypher
  • Graph Data Model
  • JavaScript
  • Node.js
  • Python
  • React.js
  • 웹 앱

에이치시스템즈의 LogTree는 Neo4j 기반 GraphRAG 플랫폼으로, 데이터를 자동으로 지식그래프화하고 자연어 질의로 즉시 답을 제공합니다.

👉 에이치시스템즈 홈페이지

728x90
반응형

+ Recent posts