티스토리 뷰

Common Mappings

6.0 버전 이상에서는 필수가 됨.

Field types

curl -XPUT 127.0.0.1:9200/movies -d '
{
    "mapping": {
        "properties": {
            "year": {"type": "date"}
        }
    }
}
'

mapping은 schema 정의이다. 위의 예시와 같이 날짜 형식의 데이터를 단순히 . 혹은 -로 연결된 문자열이 아닌 date type으로 해석하도록 지정하는 것이다.
이 외에도 매핑은 String, byte, short, long, float, double, boolean, date 등으로도 지정할 수 있다. elasticsearch는 이 모든 종류를 type으로 인식하고 처리할 수 있다.

Field Index

또한 mapping을 통해 field의 '전체 텍스트 검색' 여부를 설정할 수 있다.

"properties": {
    "genre": {
        "index": "not_analyzed"
    }
}

예시처럼 {"index": "not_analyzed"}라고 설정하면 해당 정보를 '전체 택스트 검색'의 대상으로 포함하지 않고 태그가 추가되는 보조 정보정도로만 사용한다는 뜻이다.

Field Analyzer

  • 문자 필터를 가진다. 예를 들어, HTML 인코딩을 제거하거나, &기호를 단어로 바꿀 수 있으며 토크나이저를 사용하여 토큰화(공백이나 구두점 또는 특수 문자를 기준으로 문자열을 분할할 방법을 지정하는 것)할 수도 있다. 또한 모든 문자를 소문자화 시키거나 어간, 동의어, 중지 단어 등의 작업을
    할 수 있는 필터도 제공한다.
  • Analyzer는 기본적으로 세 가지 기능이 있다.
    • Character Filters
      • HTML 인코딩 제거 혹은 &기호를 단어로 변경 등의 기능
      • 동일한 Analyzer를 검색 쿼리와 색인화된 정보에 적용하면 둘 사이에 있을 수 있는 모든 차이점을 제거할 수 있다.
      • '그리고' 라는 단어와 '&' 기호를 매핑하는 Analyzer를 검색 쿼리와 색인화중인 데이터에 모두 적용한다면 '&' 기호나 '그리고' 라는 단어 무엇을 검색하는지와 상관없이 역색인으로부터 '&' 기호에 대한 결과를 받게 된다.
    • Tokenizer
      • 무엇이 단어인지 어떻게 알 수 있을까? 검색어는 어떻게 분류될까? 이는 토크나이저 선택에 따라 달라진다.
      • 구두점이나 공백 또는 문자가 아닌 모든 부분을 기준으로 문자열을 분할할 수 있다.
    • Token Filter
      • Lowercasing (소문자화)
        • 검색에서 대소문자를 구분하지 않으려면 토큰 필터링을 사용하면 된다.
        • 토큰 필터를 사용하여 모두 소문자화 시키고 싶다면 검색 쿼리와 색인화 대상에 동일한 Analyzer와 token filter를 적용하면 대소문자 구분이 사라진다.
      • stemming (어간)
        • box, boxes, boxing, boxed의 단어를 모두 box라는 단어에 일치시켜 검색한다.
      • synonyms (동의어)
        • big을 검색했을 때, large도 포함하는 문서도 나타나길 원한다면 synonyms를 사용하여 정규화하면 된다.
      • stopwords (중지 단어 혹은 불용어)
        • the, in과 같이 별 뜻이 없는 작은 단어들을 제외하고 싶다면 stopwords 필터를 적용해 모든 항목을 색인화하지 않도록 할 수 있다.
        • 구문 검색에 stopwords를 사용하지 않는 이유는 'to be or not to be'와 같이 모든 단어가 중지 단어일 수 있기 때문이다.
        • 따라서 신중히 사용해야한다.
  • 여러가지 종류의 Analyzer가 있다.
    • standard
      • 단어 경계선에서 분할하며 구두점을 제거하고 소문자화한다.
      • 언어를 잘 모른다면 좋은 선택지가 될 수 있다.
    • simple
      • 글자가 아닌 곳에서 단어를 분할하고 소문자화한다.
    • whitespace
      • 공백에서 단어를 분할하지만 소문자화하지는 않는다.
      • 구두점이 보존되기 때문에 이를 잘 고려해야한다.
    • langauge
      • 사용할 언어를 특정한다.

JSON / REST를 통해 단일 영화정보 가져오기

문서를 색인으로 가져와보도록 하자.

Insert

curl -XPUT 127.0.0.1:9200/movies/_doc/109487 -d '
{
    "genre": ["IMAX", "Sci-Fi"],
    "title": "Interstellar",
    "year": 2014
}
'

실제 환경에서는 Java나 개발중인 웹 프레임워크 혹은 애플리케이션을 통해 HTTP REST QEURY를 요청하겠지만 현재는 연습의 목적으로 curl을 사용한다.
위의 예제는 PUT 요청을 생성해 127.0.0.1:9200으로 보낸다. 이어서 index 이름인 movies를 지정하고, 해당 영화에 할당하는 고유 ID를 입력한다. 현재 사용하는 데이터셋에서 인터스텔라 영화의 고유 ID는 109487이기에 그대로 사용하고 request body를 작성해주면 된다.

먼저 사용할 mapping을 생성해준다.

curl -XPUT 127.0.0.1:9200/movies -d '
{
    "mapping": {
        "properties": {
            "year": {
                "type": "date"
            }
        }
    }
}
'

curl -XGET 127.0.0.1:9200/movies/_mapping 명령어로 정상적으로 mapping이 생성되었는지 확인한다.

이제 영화를 삽입하고 생성한 mapping을 적용시켜보자.

curl -XPOST 127.0.0.1:9200/movies/_doc/109487 -d '
{
    "genre": ["IMAX", "Sci-Fi"],
    "title": "Interstellar",
    "year": 2014
}
'

이제 데이터를 가져와서 실제로 저장이 잘 되었는지 확인해보자.

curl -XGET 127.0.0.1:9200/movies/_search?pretty
  • pretty는 탭과 줄바꿈을 사용해 결과를 보기 좋게 변환해준다.

Bulk API로 한 번에 여러 영화정보 삽입하기

이제 한 편의 영화는 index로 불러올 수 있다. 하지만 많은 영화나 문서서를 한 번에 가져오거나 기존 데이터 셋 혹은 전체 데이터 세트를 한번에 가져와야하는 경우도 많이 발생한다. 따라서 REST 쿼리와 JSON 형식을 사용하여 많은 문서를 한 번에 가져오는 방법을 알아보자.

  • curl -XPUT 127.0.0.1:9200/_bulk -d '~~'
    주의해야할 점으로는 Elasticsearch는 모든 특정 문서를 주어진 shard로 hash하기 때문에 개별 문서를 한 번에 하나씩 처리해야한다는 것이다. 따라서 여러 영화에 대한 데이터를 삽입하고 싶은 경우 각 영화 한편에 대한 정보를 create 후 다른 영화에 대한 데이터를 create 하는 방식으로 삽입해주어야 한다. 예를 들면 다음과 같다.
{ "create" : { "_index" : "movies", "_id" : "135569" } }
{ "id": "135569", "title" : "Star Trek Beyond", "year":2016 , "genre":["Action", "Adventure", "Sci-Fi"] }
{ "create" : { "_index" : "movies", "_id" : "122886" } }
{ "id": "122886", "title" : "Star Wars: Episode VII - The Force Awakens", "year":2015 , "genre":["Action", "Adventure", "Fantasy", "Sci-Fi", "IMAX"] }
{ "create" : { "_index" : "movies", "_id" : "109487" } }
{ "id": "109487", "title" : "Interstellar", "year":2014 , "genre":["Sci-Fi", "IMAX"] }
{ "create" : { "_index" : "movies", "_id" : "58559" } }
{ "id": "58559", "title" : "Dark Knight, The", "year":2008 , "genre":["Action", "Crime", "Drama", "IMAX"] }
{ "create" : { "_index" : "movies", "_id" : "1924" } }
{ "id": "1924", "title" : "Plan 9 from Outer Space", "year":1959 , "genre":["Horror", "Sci-Fi"] }

위의 예시를 실습 디렉토리의 movies.json 이라는 폴더로 저장하고, curl -XPUT 127.0.0.1:9200/_bulk?pretty --data-binary @movies.json 커맨드를 입력해주면 movies.json 파일이 모두 정상적으로 elasticsearch에 저장되는 것을 확인할 수 있다. 이렇게 여러개를 한번에 저장하는 방법이 있다.

Elasticsearch에서 데이터 업데이트

이전의 대량의 데이터를 삽입하는 방법은 만약 동일한 데이터가 이미 elasticsearch에 존재한다면 conflict가 발생한다는 문제가 있다. 그렇다면 이미 indexed 된 문서를 어떻게 변경하거나 업데이트 해야할까?
elasticsearch 문서는 불변이기 때문에 일단 작성된 문서는 실제로 변경할 수는 없지만 elasticsearch는 입력한 모든 문서에 자동으로 _version필드를 생성하기 때문에 문서를 업데이트 하기 위해 증가한 _version 번호로 문서의 새 복사본을 작성한다. 중요한 것은 문서의 고유 ID와 버전을 함께 사용하는 것이다. 이렇게 하면 지정된 문서의 여러 버전을 가질 수 있으며 Elasticsearch는 자동으로 사용자가 작성한 최신 버전을 사용한다.
따라서 Elasticsearch에 업데이트 요청을 하면 완전히 새로운 문서가 생성되고, 새 문서는 증가한 버전 번호로 작성된 후 이전 문서는 '삭제'표시가 되며, 이 '삭제'표시가 된 문서는 필요할 때마다 정리 작업을 수행하여 예전 버전을 제거한다.

업데이트는 다음과 같이 수행할 수 있다.

curl -XPOST 127.0.0.1/movies/_doc/109487/_update -d '
{
    "doc": {
        "title": "Interstellar"
    }
}
'

이 명령은 Document ID 109487의 title field만 변경하며, 이외의 데이터는 이전의 기존 버전에 있는 것을 복사해오고 새 버전 번호를 가진 새 복사본이 생성되는 것이다.

Elasticsearch에서 데이터 삭제

REST 중 DELETE를 사용하면 된다.

  • curl -XDELETE 127.0.0.1:9200/movies/_doc/58559
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함