<아랑고DB> 3. 아랑고DB 사용해보기

|
이번 글에서는 아랑고DB의 쉘을 사용해 아랑고DB의 기초 사용법을 배워보려고 한다. 사실 실제 작업은 Python 커넥터를 통해서 하는 경우가 대부분이지만, 실체를 알기 위해서는 직접 쉘로 붙어보는 것이 가장 효과적이라고 생각하기 때문이다.

들어가기에 앞서

  • 아랑고DB가 이미 설치되어있다고 가정한다. 만약 아직 설치되지 않았다면 여기를 보고 따라 설치해보자.
  • 또한 아랑고쉘은 JavaScript Shell 환경을 사용한다고 한다. 따라서 JS문법을 그대로 이용할 수 있다.

1. 데이터베이스 수준 명령어

초기 실행은 arangosh 명령어를 통해 한다. 그리고 초기에 입력했던 root 계정의 비밀번호를 입력해주면 된다. 쉘에 접속 후 tutorial 명령어를 입력하면 간단한 튜토리얼도 따라할 수 있으니 참고하자.

쉘에 접속했을 때 기본 데이터베이스는 _system 이다. 이제 movies라는 데이터베이스를 만들고, titles라는 도큐먼트 컬렉션을 만들어 볼 것이다. 데이터베이스 이름을 짓는 Naming Convention도 읽어보자.

// 현재 아랑고DB에 있는 데이터베이스들의 목록을 조회한다 
127.0.0.1:8529@_system> db._databases()
[ 
  "_system" 
]

// movies라는 데이터베이스를 만든다
127.0.0.1:8529@_system> db._createDatabase('movies')
true

// 생성된 것을 확인할 수 있다
127.0.0.1:8529@_system> db._databases()
[ 
  "_system", 
  "movies" 
]

// 데이터베이스를 변경해준다
127.0.0.1:8529@_system> db._useDatabase('movies')
true

// 컬렉션을 생성해준다. 탭을 눌러 자동완성 기능을 애용하자
// 컬렉션은 Edge Collection과 Document Collection으로 나뉘는데, 여기서는 단순히 도큐먼트의 집합을 생성할 예정이다.
127.0.0.1:8529@movies> db._createDocumentCollection('titles')
[ArangoCollection 139708, "titles" (type document, status loaded)]

127.0.0.1:8529@movies> db._collections()
[ 
  [ArangoCollection 139603, "_analyzers" (type document, status loaded)], 
  [ArangoCollection 139618, "_appbundles" (type document, status loaded)], 
  [ArangoCollection 139615, "_apps" (type document, status loaded)], 
  [ArangoCollection 139606, "_aqlfunctions" (type document, status loaded)], 
  [ArangoCollection 139621, "_frontend" (type document, status loaded)], 
  [ArangoCollection 139600, "_graphs" (type document, status loaded)], 
  [ArangoCollection 139612, "_jobs" (type document, status loaded)], 
  [ArangoCollection 139609, "_queues" (type document, status loaded)], 
  [ArangoCollection 139708, "titles" (type document, status loaded)] 
]

도큐먼트 컬렉션과 엣지 컬렉션은 데이터 모델의 성격에 따라 구분되는 컬렉션이다. 도큐먼트 컬렉션은 그래프DB에서 노드(버텍스)의 개념이고, 엣지 컬렉션은 이 노드들 사이의 관계를 나타내는 컬렉션이다.

2. 컬렉션 수준 명령어

이제 생성된 컬렉션 안에 도큐먼트를 추가해보자. 사실 쉘에서 데이터를 다루는 방식은 불편하기 때문에 이런 방법도 있다 정도로만 끝내려고 한다. 컬렉션 수준에서 사용하는 명령어들은 db.컬렉션명의 형태에 CRUD 관련 명령어들이 붙는 형태이다. 예를 들어 다음과 같은 식이다.

  • Create : db.titles.save({name : “Harry”})
  • Read : db.titles.toArray()
  • Update : db.titles.update(‘140292’, {name : “Sally”})
  • Delete : db.title.remove(‘140292’)

CREATE

save 명령어는 도큐먼트를 저장하기 위해 쓰이는데, 모든 데이터의 검색에서 쓰이는 _key 값을 직접 설정할 수 있다.

  • _key는 컬렉션 레벨에서 고유한 값이다.
  • _id는 데이터베이스 레벨에서 고유한 값이며, ‘{컬렉션명}/{_key 값}’ 의 형태이다.
  • 자세한 내용은 여기를 읽어보기

_key값을 어떻게 설정하느냐에 따라 쿼리의 효율이 하늘과 땅 차이이기 때문에 설계를 잘 해보자. 키 이름의 네이밍 컨벤션도 확인해보자.

// Harry Potter 1이라는 도큐먼트를 생성한다. _key값을 지정해주지 않으면 자동으로 생성해준다.
127.0.0.1:8529@movies> db.titles.save({title: "Harry Potter 1"})
{ 
  "_id" : "titles/140292", 
  "_key" : "140292", 
  "_rev" : "_dNTU1bG---" 
}

// JS 문법을 활용해 반복문도 쓸 수 있다.
127.0.0.1:8529@movies> for (var i=0; i< 10; ++i) {
...> db.titles.save({name: "Harry Potter" + i});
...> }
{ 
  "_id" : "titles/141195", 
  "_key" : "141195", 
  "_rev" : "_dNT028W--A" 
}

READ

데이터를 조회하는 방법도 간단하다.

  • toArray()를 통해 해당 컬렉션의 전체 도큐먼트를 조회하거나
  • byExample({조건})의 형태로 조건에 해당하는 도큐먼트만 조회할 수 있다
// toArray() 함수를 통해 컬렉션의 모든 도큐먼트를 조회한다
127.0.0.1:8529@movies> db.titles.toArray()
[ 
  { 
    "_key" : "140292", 
    "_id" : "titles/140292", 
    "_rev" : "_dNTU1bG---", 
    "title" : "Harry Potter 1" 
  } 
]

// 위에서 _key값은 설정하지 않았지만, 직접 도큐먼트를 조회하기 위해서는 document 함수에서 _key값을 불러주면 된다.
// 이렇게 _key값으로 도큐먼트를 조회하는 방법이 도큐먼트를 조회하는 가장 빠른 방법임을 새겨두자
127.0.0.1:8529@movies> db.titles.document('140292')
{ 
  "_key" : "140292", 
  "_id" : "titles/140292", 
  "_rev" : "_dNTU1bG---", 
  "title" : "Harry Potter 1" 
}

// 컬렉션 이름을 문자화하여 호출할 수도 있다
127.0.0.1:8529@movies> db._document("titles/140292")
{ 
  "_key" : "140292", 
  "_id" : "titles/140292", 
  "_rev" : "_dNTU1bG---", 
  "title" : "Harry Potter 1" 
}
 
// 이름이 Harry Potter8인 도큐먼트 조회
127.0.0.1:8529@movies> db.titles.byExample({name : "Harry Potter8"}).toArray();
[ 
  { 
    "_key" : "141193", 
    "_id" : "titles/141193", 
    "_rev" : "_dNT028W--_", 
    "name" : "Harry Potter8" 
  } 
]

UPDATE

도큐먼트 업데이트는 update(업데이트 매치 조건, 업데이트 할 필드) 형태로 쓴다. 여기서 주목할 점은 리턴값으로 _rev, _oldRev를 제공한다는 점이다. rev는 revision의 약자로 일종의 도큐먼트의 버전과 같은 개념인데, 아랑고쉘의 tutorial에서는 이 revision 이 조건부 수정을 위한 용도로 쓰인다고 말한다. 즉, 도큐먼트를 동시에 업데이트 하는 동시성 문제가 발생했을 때 상황에 따라서 revision 개념을 사용하면 의도하지 않았던 결과를 막을 수 있다는 개념인 것 같다.

// revision 설명 전에 잠깐 보면, 업데이트를 하면 기존의 old revision과 새롭게 바뀐 revision을 리턴해준다
// 즉, 도큐먼트의 버전이 바뀌었다고 안내해준다
127.0.0.1:8529@movies> db.titles.update('140292', {series : 1})
{ 
  "_id" : "titles/140292", 
  "_key" : "140292", 
  "_rev" : "_dNTcxl6---", 
  "_oldRev" : "_dNTU1bG---" 
}
  
// 여기서부터는 아랑고쉘에서 쉽게 설명해주는 부분이다
// 우선 도큐먼트를 조회해 doc이라는 변수에 저장한다
 > doc = db._document("places/example1");
// 그리고 아래 업데이트를 수행하면, 이는 별 문제없이 성공한다. 이때, 업데이트가 성공했기 때문에 기존의 revision 값은 변경됐다 
> db._update("places/example1", { someValue: 23 });
// 아래 업데이트는 위에서 선언한 doc을 기준으로 한다. 하지만, doc의 revision은 이미 위 업데이트 이후 old revision이 되었기 때문에 업데이트는 실패하게 된다. 
> db._update(doc, { someValue: 42 });
JavaScript exception in file '/usr/share/arangodb3/js/client/modules/@arangodb/arangosh.js' at 99,7: ArangoError 1200: conflict, _rev values do not match
!      throw error;
!      ^
stacktrace: ArangoError: conflict, _rev values do not match

DELETE

도큐먼트를 삭제하는 것도 매우 간단하다. 마찬가지로 도큐먼트의 _id_key 값을 remove() 함수에 전달하면 된다.

// _id로 지우기
127.0.0.1:8529@movies> db._remove("titles/140292");
{ 
  "_id" : "titles/140292", 
  "_key" : "140292", 
  "_rev" : "_dNTpPd----" 
}
  
// _key로 지우기
127.0.0.1:8529@movies> db.titles.remove("140292");
  

3. AQL 실행하기

AQL은 Arango Query Lang의 약자로, SQL처럼 편리하게 아랑고DB를 조회하고, 횡단하기 위한 언어이다. 아랑고쉘에서도 AQL을 실행할 수 있으며, 어떻게 하는지만 언급하고 나중에 제대로 배워보기로 한다.

// 쿼리는 멀티라인이기 때문에 키보드 숫자 1 옆의 `(backtick이라고 부름) 로 쿼리를 감싸주도록 한다
// 아래 AQL은 titles 컬렉션에 있는 모든 도큐먼트를 리턴하는 쿼리다
// db.titles.toArray()와 동일하다
127.0.0.1:8529@movies> db._query(`
...> FOR title in titles
...> RETURN title`)

4. 어디까지 왔나

다음 글에서는 아랑고DB의 Web UI를 통해 우리가 넣은 데이터를 살펴보고, 다양한 기능들을 살펴보려고 한다.

  1. 아랑고DB란? 왜 쓰는가?
  2. 아랑고DB 세팅하기 on Ubuntu
  3. (지금 보고있는 글)아랑고DB 쉘로 붙어서 명령어 체험해보기, 실체 파악해보기
  4. AQL(Arango Query Lang) 배워보기 1
  5. AQL(Arango Query Lang) 배워보기 2 - RETURN / UPDATE
  6. AQL(Arango Query Lang) 배워보기 3 - REPLACE / UPSERT / REMOVE
  7. 그래프 개념잡기
  8. 그래프 횡단하기 Graph Traversal
  9. 데이터 모으기 COLLECT / AGGREGATE / MIN_BY, MAX_BY
  10. 프로젝트. 그래프를 통한 영화 추천시스템 만들어보기 1
  11. 프로젝트. 그래프를 통한 영화 추천시스템 만들어보기 2 (최종편)

<아랑고DB> 2. 아랑고DB 세팅하기 on Ubuntu

|
이번 글에서는 아랑고DB를 세팅하는 방법에 대해 알아보려고 한다. 로컬(본인 컴퓨터나 노트북)에서 작업해도 좋고 개발용 서버가 있다면 서버에서 해도 좋다. 나는 AWS에서 제공하는 프리티어 EC2를 사용 중이다.

1. 설치하기

설치는 매우 간단하다. 아랑고DB 공식 홈페이지에 있는 커뮤니티 버전 중, 본인 환경에 맞는 것을 설치하면 된다. 여기서는 Ubuntu 버전을 설치한다.

// 아래 curl 명령어가 오류난다면 권한 문제일 경우가 많다. sudo를 붙이거나 폴더의 권한을 바꿔주자.
curl -OL https://download.arangodb.com/arangodb38/DEBIAN/Release.key
sudo apt-key add - < Release.key
                                
echo 'deb https://download.arangodb.com/arangodb38/DEBIAN/ /' | sudo tee /etc/apt/sources.list.d/arangodb.list
sudo apt-get install apt-transport-https
sudo apt-get update
                                
// 약 300mb 정도의 여유 공간이 필요하다
// 설치 화면이 나타나면, root 권한의 비밀번호를 설정하게 된다. 꼭 기억해두자.
// 자동 업데이트나 업데이트 시 백업 여부는 개발용이기 때문에 No,No로 해두었다.
sudo apt-get install arangodb3=3.8.2-1

이제 설치가 완료되었다. arangosh 명령어를 통해 라이브된 아랑고DB 쉘에 접속할 수 있고, 혹은 service arangodb3 status 명령어를 통해 서비스에 등록되어 정상 설치된 것을 확인할 수 있다.

2. 설치 경로에 관한 이야기

우분투에서 프로그램이 설치되는 경우, 주로 찾아보는 경로를 잠깐 정리해보자면, 아래와 같다. 이 경로들은 대부분 다른 프로그램들에서도 공통으로 쓰이며, 대개 /etc 경로의 해당 config 파일을 열어보면 자세한 설정들이 나와있다.

  • /etc/arangodb3/ : 각종 설정 파일이 저장된 공간
  • /var/lib/arangodb3 : 아랑고DB의 파일들이 저장되는 곳
  • /var/log/arangodb3 : 아랑고DB의 로그가 쌓이는 곳

3. 설정 파일과 Web UI 세팅하기

이제 아랑고DB의 설정 파일을 한 번 살펴보자.

cd /etc/arangodb3
sudo vim arangod.conf

여기서 server 항목을 살펴보면, endpoint가 tcp:127.0.0.1:8529로 설정된 것을 볼 수 있다. 실제로 아랑고DB의 Web UI에 접속하려면 브라우저에 본인의 서버 주소에 8529 포트를 붙여 접속할 수 있다. 예를 들어, EC2를 쓰는 내 경우 ec2-x-x-x-x.ap-northeast-2.compute.amazonaws.com:8529로 붙을 수 있다.

하지만 이때 접속이 되지 않는다면, 1) endpoint를 0.0.0.0:8529로 변경해본다. 이에 관한 자세한 내용은 여기를 읽어보기 2) 그래도 안 된다면 본인 서버의 보안을 확인한다. (EC2의 경우 보안그룹의 inbound traffic이 내 주소에 열려있는지..) 3) 그래도 안 된다면 아랑고DB의 가이드를 살펴본다.

위 과정을 거쳐서 다시 브라우저로 접속해보면 아랑고 Web UI가 설치된 것을 확인할 수 있다! 아랑고DB의 강력하고 편리한 기능이기 때문에 얼굴을 기억해두자.

초기 세팅했던 root 계정과 비밀번호로 접속하면 _system 데이터베이스로 접속할 수 있다. _system db는 다른 데이터베이스를 생성하고, 시스템 관련 설정을 할 수 있는 기본 데이터베이스라고 보면 된다.

4. 어디까지 왔나

다음 글에서는 아랑고DB의 데이터 구조에 대해 간단하게 알아보고, 아랑고 쉘에서 명령어를 통해 여러가지 CRUD 작업을 해서 실체를 익혀보려고 한다.

  1. 아랑고DB란? 왜 쓰는가?
  2. (지금 보고있는 글)아랑고DB 세팅하기 on Ubuntu
  3. 아랑고DB 쉘로 붙어서 명령어 체험해보기, 실체 파악해보기
  4. AQL(Arango Query Lang) 배워보기 1
  5. AQL(Arango Query Lang) 배워보기 2 - RETURN / UPDATE
  6. AQL(Arango Query Lang) 배워보기 3 - REPLACE / UPSERT / REMOVE
  7. 그래프 개념잡기
  8. 그래프 횡단하기 Graph Traversal
  9. 데이터 모으기 COLLECT / AGGREGATE / MIN_BY, MAX_BY
  10. 프로젝트. 그래프를 통한 영화 추천시스템 만들어보기 1
  11. 프로젝트. 그래프를 통한 영화 추천시스템 만들어보기 2 (최종편)

<아랑고DB> 1. 아랑고DB 알아보기

|
아랑고DB는 회사에서 프로젝트를 진행하며 다루었던 데이터베이스이다. 초기 진입 자체는 간단했지만 사용함에 있어 까다로운 점들도 많았고, 깨달은 점도 많았다. 블로그 첫 글을 장식하기에 적당한 주제일 것 같아 선정했고, 실제 사용 사례나 경험했던 점들을 공유하고자 한다.

1. 아랑고DB란? 언제 사용해야할까?

ArangoDB, 아랑고DB는 데이터베이스의 한 종류로써 Native Multi-Model Database를 표방하고 있다. 멀티 모델이란 키-값, 도큐먼트, 그래프 형태 등 다양한 모델을 지원하는 모델인데, 이를 단일 엔진에서 구현하기 때문에 native라는 표현을 썼다고 한다. 자세한 내용은 여기를 읽어보자.

그럼 왜 아랑고DB를 써야할까? 이 질문은 왜 그래프DB를 써야할까?라는 질문에 대한 답을 먼저 해야 할 것 같다.

그래프DB는 데이터를 점(Vertex)과 점을 잇는 선(Edge)으로 표현한 데이터베이스다.

  • 그래프 구조로 되어있기 때문에 두 객체 사이의 관계를 표현하기에 최적화되어있다.
  • 객체끼리 엣지로 연결되어 있기 때문에 여러 컬렉션에 흩뿌려진 데이터에 접근하기가 쉽다.
  • 그래프를 횡단하기 위한 직관적인 그래프 명령어가 존재한다.
  • 그리고 그래프 횡단을 통해 기존 RDBMS와 NoSQL 데이터베이스에서는 매우 비효율적이거나, 절대 쿼리로 만들 수 없었던 데이터들을 뽑아낼 수 있다.

그럼 그래프DB 중에서, 왜 아랑고DB인가?

  • 커뮤니티 에디션에서 다중 데이터베이스를 제공한다 (Neo4J는 1개의 DB밖에 생성을 못한다… 여기 참고)
  • 그래프 쿼리인 AQL이 직관적이며 간편하다
  • WebUI를 제공한다
  • 빠르게 그래프 개념을 익히기 좋다

그래프DB의 1등은 Neo4J이다. 하지만 커뮤니티 에디션이 단일 데이터베이스밖에 지원하지 않기 때문에 이것저것 테스트하기가 번거로웠다.

그래서 나는 그래프DB의 개념을 익히고, 재밌게 연습하기에는 아랑고DB가 최적이라고 생각한다. AQL도 상당히 직관적이기 때문에 배우는 데 진입장벽이 낮기 때문이다.

2. 아랑고DB의 사용 예시

아랑고DB는 아래와 같은 상황들에서 제 힘을 발휘한다. 공통적으로 볼 때, 여러 컬렉션을 모두 돌면서 데이터를 탐색하는 상황에서 아랑고DB는 가장 강력하다.

다른 RDBMS나 NoSQL에서 많은 테이블/컬렉션을 하나의 쿼리에 탐색하는 상황을 역으로 생각해보면 얼마나 번거롭고 비효율적인 일인지 알 수 있을 것이다.

예시 1 - 어제 방문한 유저 중, 오늘 재방문한 유저 찾기

관계형DB를 사용한다면, 아래 t1에 t2를 unique_id로 left join하여 값이 매치하는 경우 어제도 방문했다고 결론지을 수 있을 것이다.

  • t1 = 오늘 방문한 유저의 unique id 목록
  • t2 = 어제 방문한 유저의 unique id 목록

예시 2 - 지난 한 달간 방문한 유저 중, 오늘 재방문한 유저 찾기

그럼 여기서 더 나아가, 어제가 아닌 지난 한 달 동안 방문한 유저들을 대상으로 한다면 어떻게 될까? t2가 조회해야 하는 데이터 양은 1일 -> 30일로 30배가 늘어났다. 시간단위로 파티셔닝을 해두었다면 이는 t2 테이블을 읽는 데에만 훨씬 더 많은 시간이 소요됨을 의미한다. 보통 이렇게 되면 이전 30일치의 유저 unique_id를 따로 캐싱해두고 빠르게 꺼내는 방식을 택하는 게 나을 것이다.

예시 3 - 예시2의 유저들의 최초 유입 경로 찾기

그럼 여기서 더 깊은 분석을 한다고 가정해보자. 지난 한 달 간 방문한 적이 있는 유저 중, 오늘 재방문한 유저들이 최초로 이 웹사이트에 방문한 경로를 알고싶다. 여기서부터 머리가 복잡해지기 시작한다. t1과 t2를 join하여 타겟 유저 그룹을 분리해내는 것까지는 시간이 오래 걸릴 뿐 별 문제가 없었는데, 이제 이 타겟 유저 그룹의 개별 유저마다 최초의 유입 경로를 찾아야 한다. 마찬가지로 DB가 시간 단위로 파티셔닝 되어있다면, 도대체 조회 기간을 언제부터 산정해야할까?

이러한 종류의 쿼리들은 관계형DB에서도 구현은 가능하지만, 실제 프로덕션 수준으로 끌어오기까지는 꽤나 설계가 필요할 것이다. 나는 이러한 경우에 그래프DB를 써야한다고 본다.

  1. 데이터의 출발점이 특정 인덱스/파티션에 한정(위 예시에서는, 조회하는 기간)되는게 아니고 여러 컬렉션에서 출발할 수 있고,
  2. 내가 필요한 데이터 점들을 횡단(traverse)하여 원하는 값을 구성해낼 수 있고
  3. 이 과정에서 필요한 점들만을 효율적으로 방문할 수 있기 때문이다.

3. Performance

아랑고DB의 성능 벤치마크는 여기서 확인할 수 있다. 사실 그래프DB에서 깊은 뎁스로 횡단을 하다보면 생각만큼 효율이 나지 않을 때도 많다. 기회가 된다면 이런 경우에 대해 어떻게 쿼리 최적화를 했는지도 공유해야겠다.

4. 앞으로의 계획

앞으로의 글들은 아래의 순서로 진행될 것 같다. 쓰고보니 많아보이지만 핵심 위주로만 슥슥 넘어가려고 한다. 블로그의 첫 개시인데, 게으름피우지 않고 부지런히 써봐야겠다!

  1. (지금 보고있는 글)아랑고DB란? 왜 쓰는가?
  2. 아랑고DB 세팅하기 on Ubuntu
  3. 아랑고DB 쉘로 붙어서 명령어 체험해보기, 실체 파악해보기
  4. AQL(Arango Query Lang) 배워보기 1
  5. AQL(Arango Query Lang) 배워보기 2 - RETURN / UPDATE
  6. AQL(Arango Query Lang) 배워보기 3 - REPLACE / UPSERT / REMOVE
  7. 그래프 개념잡기
  8. 그래프 횡단하기 Graph Traversal
  9. 데이터 모으기 COLLECT / AGGREGATE / MIN_BY, MAX_BY
  10. 프로젝트. 그래프를 통한 영화 추천시스템 만들어보기 1
  11. 프로젝트. 그래프를 통한 영화 추천시스템 만들어보기 2 (최종편)