Elasticsearch에서의 데이터
- 논리적 구조(Logical layout)
- Document는 mapping type으로 그룹핑 되어 있고, type 이라고 부른다.
- index>type
- 물리적 구조(Physical layout)
- 엘라스틱서치는 인덱스르 샤드로 분배하는데 이것은 클러스터로 만들어서 통합할 수도 있다.
- Node > primary(index 포함) , replica 또는 secondary(index 포함)
document
- 문서는 색인화할 수 있는 기본 정보 단위이다.
- JSON(JavaScript Object Notation) 형식
- 하나의 색인에 원하는 개수의 문서를 저장할 수 있다.
index
- 색인은 비슷한 특성을 가진 문서의 모음.
- 색인은 이름(모두 소문자)으로 식별되며, 이 이름은 색인에 포함된 문서에 대한 색인화, 검색, 업데이트, 삭제 작업에서 해당 색인을 가리키는 데 쓰인다.
- 단일 클러스터에서 원하는 개수의 색인을 정의할 수 있다.
type (Deprecated 7.x & Removed 8.x)
- 하나의 색인에 하나 이상의 유형을 정의할 수 있다. (Before 6.x)
[Removal of Types](https://www.elastic.co/guide/en/elasticsearch/reference/master/removal-of-types.html)
document 색인
색인은 하나 이상의 문서를 색인에 저장하는 것을 의미한다. 관계형 데이터베이스에서 레코드를 추가하는 개념과 유사하다.
curl -X PUT "localhost:9200/twitter/_doc/1" -H 'Content-Type: application/json' -d' { "user" : "kimchy", "post_date" : "2009-11-15T14:12:12", "message" : "trying out Elasticsearch" } { "_index": "twitter", "_type": "_doc", "_id": "1", // 명시적으로 주었으므로 1 "_version": 1, // Optimistic Concurrency Control(낙관적 동시성 제어)에 대한 색인된 문서 버전 "result": "created", // 레코드 생성 여부 "_shards": { "total": 2, "successful": 1, "failed": 0 }, "_seq_no": 0, "_primary_term": 1 }
색인 절차
- ID 나 라우팅/부모 메타데이터에 따라 호출을 올바른 샤드로 라우팅, 클라이언트 ID 를 제공하지 않으면 새로운 ID 를 생성한다.
- 전송한 JSON 유효성 검증
- 매핑에 따라 JSON 처리, 문서에 새 필드가 있고 매핑을 변경할 수 있다면 새 필드를 매핑에 추가한다.
- 샤드에서 문서 색인, ID 가 이미 있다면 변경한다.
- 중첩 문서를 포함한다면 추출한 다음 별도로 처리한다.
- 저장된 문서 관련 정보를 반환한다. (ID 와 버전) 데이터를 색일할 올바른 ID 를 선택하는 것이 중요하다. ID 를 제공하지 않으면 색인 단계에서 elasticsearch 는 문서에 새 ID 를 부여한다.
-- {id} 를 제거하고 response 데이터를 확인해본다. (PUT 대신에 POST 호출임을 주의하자!) curl -X POST "localhost:9200/twitter/_doc" -H 'Content-Type: application/json' -d' { "user" : "kimchy", "post_date" : "2009-11-15T14:12:12", "message" : "trying out Elasticsearch2" } '
매핑에 따라 색인 단계에서 다른 작업(레플리카 전파, 중첩 처리 등)이 수행된다.
Automatic Index Creation
색인이 존재하지 않는 경우, 자동으로 색인을 생성하고 구성된 색인 템플릿을 적용한다. Automatic index creation은 action.auto_create_index.setting
값에 의해 관리된다. 이 값은 true 가 기본, 즉 index 는 항상 자동으로 생성된다. 이 설정값은 특정 패턴과 일치하는 index에 대해서만 자동 생성을 적용할 수 있으며, false로 변경하여 완전히 비활성화할 수 있다.
-- 패턴으로 적용하는 경우 curl -X PUT "localhost:9200/_cluster/settings" -H 'Content-Type: application/json' -d' { "persistent": { "action.auto_create_index": "twitter,index10,-index1*,+ind*" } } ' -- 비활성화 / 활성화 curl -X PUT "localhost:9200/_cluster/settings" -H 'Content-Type: application/json' -d' { "persistent": { "action.auto_create_index": "false" } } '
추가 파라미터
Elasticsearch 는 문서 색인 방법을 제어하기 위해 URL에 다수의 쿼리 파라미터를 전달할 수 있다.
- routing: 어떤 샤드가 색인에 사용될지 지정
- timestamp: 문서 색인에 사용할 타임스탬프, 매핑에 활성화 되어 있어야 한다.
- replication(sync/async): async 로 설정되면 프라이메어리 샤드 에서 색인 작업을 동기로 실행하고 세컨더리 샤드 에서는 비동기로 실행한다.
- version: 현재 색인 버전이 전달된 버전과 매치될 경우에만 색인한다.
- os_type: 문서를 생성하게 강제하는 데 사용할 수 있다. 같은 ID 를 가진 문서가 있다면 색인은 실패한다.
- refresh: 문서를 색인한 후에 강제로 새로 고침을 해서 색인 직후 문서를 검색할 수 있게 한다.
- timeout: 프라이메어리 샤드가 사용 가능해질 때까지 대기하는 시간을 정의한다.
document 조회
문서를 색인한 후에 어플리케이션 수명이 끝날 때까지 검색된다.
curl -X GET "localhost:9200/twitter/_doc/1" -- 성공 (데이터 있음) { "_index": "twitter", // 문서를 저장한 색인 "_type": "_doc", // 문서 타입 "_id": "1", // 문서 ID "_version": 1, // 문서 버전 "_seq_no": 0, "_primary_term": 1, "found": true, // 문서 조회 여부 "_source": { "user": "kimchy", "post_date": "2009-11-15T14:12:12", "message": "trying out Elasticsearch" } } -- 실패 (데이터 없음) { "_index": "twitter", "_type": "_doc", "_id": "0", "found": false }
다른 오버헤드 없이 문서가 담신 샤드에만 검색을 리다이렉션하고 문서 ID 는 빠른 검색을 위해 메모리에 캐시되는 경우가 많으므로 Get API 는 매우 빠르다. 원본 문서는 _source 필드가 저장돼 있을 경우에만 사용할 수 있다.
추가 파라미터
- _source: _source 검색을 해제할 수 있다. 그리고 전체 _source 에서 특정 필드만 필요한 경우, _source_includes 또는 _source_exclude 변수를 사용하여 필요한 필드만 포함 또는 필터링할 수 있다. 이는 부분 검색으로 네트워크 오버헤드를 절약할 수 있는 큰 문서에 특히 유용하다.
- stored_fields: 필드 특정 하위 집합(매핑시 stored 필드를 true로 설정한 필드)만 검색할 수 있다. 네트워크 오버헤드를 절약하거나 계산된 필드를 검색하는데 매우 유용하다.
- routing: GET 작업에 사용될 샤드를 기술한다. 문서를 조회하려면 색인할 때 사용된 라우팅이 검색할 때 사용한 것과 같아야 한다.
- refresh: GET 작업을 실행하기 전에 현재 샤드를 새로 고친다.( 색인을 느리게하고 오버헤드가 발생하므로 신중하게 사용해야 한다.)
- preference: GET 메소드를 실행하기 위해 어떤 샤드 레플리카를 선택할지 제어할 수 있다. (_primary, _local, 또는 custom value)
document 삭제
레코드를 삭제하면 문서가 있는 샤드만 접근하므로 오버헤드가 없다. 문서가 자식일 경우 부모는 올바른 샤드를 찾을 수 있도록 설정해야 한다. 문서 삭제는 DELETE 또는 delete_by_query 2가지 방법이 있다.
DELTE
curl -X DELETE "localhost:9200/twitter/_doc/1" --- 성공 { "_index": "twitter", "_type": "_doc", "_id": "1", "_version": 2, "result": "deleted", "_shards": { "total": 2, "successful": 2, "failed": 0 }, "_seq_no": 1, "_primary_term": 1 } --- 실패 { "_index": "twitter", "_type": "_doc", "_id": "1", "_version": 3, "result": "not_found", "_shards": { "total": 2, "successful": 2, "failed": 0 }, "_seq_no": 2, "_primary_term": 1 }
추가 파라미터
- routing: 삭제 작업에 샤용되는 샤드를 기술할 수 있다.
- version: 문서 업데이트를 방지하기 위해 삭제될 문서 버전을 지정할 수 있다.
- parent: 문서가 자식 문서라면 라우팅과 유사한 parent 가 필요하다.
delete_by_query
쿼리와 일치하는 모든 문서를 삭제한다.
curl -X POST "localhost:9200/twitter/_delete_by_query?scroll_size=5000" -H 'Content-Type: application/json' -d' { "query": { "term": { "user": "kimchy" } } } ' --- 성공 { "took": 139, "timed_out": false, "total": 1, // 쿼리로 매치된 문서 개수 "deleted": 1, // 삭제된 문서 개수 "batches": 1, // 문서 삭제를 위해 실행한 벌크 작업 횟수 "version_conflicts": 0, // 벌크 작업시에 버전 충돌때문에 삭제하지 못한 문서 "noops": 0, // noop 이벤트로 식제 삭제되지 않은 삭제 개수 "retries": { "bulk": 0, // 재시도한 벌크 작업 횟수 "search": 0 // 재시도한 검색 횟수 }, "throttled_millis": 0, "requests_per_second": -1.0, "throttled_until_millis": 0, "failures": [ ] }
- delete_by_query 호출은 자동으로 백프레셔를 관리한다.(서버 부하가 높은 경우 삭제 명령 비율을 줄인다.)
추가 파라미터
- conflicts: proceed 로 설정하면 버전 출동이 발생할 때 호출을 종료하지 않고 에러를 건너 뛰며, 실행을 종료한다.
- routing: 특정 샤드만 실행 대상으로 사용한다.
- scroll_size: 스크롤 및 벌크 크기(기본: 1,000)를 제어한다.
document 업데이트
제공된 스크립트를 기반으로 문서를 업데이트할 수 있도록 한다. 이 작업은 색인에서 문서를 가져오고, 스크립트를 실행하며, 결과를 색인한다. 이 특성이 작동하려면 _source 필드를 활성화해야 한다. 문서 변경은 UPDATE 또는 update_by_query 2가지 방법이 있다.
UPDATE
--- 1. 간단하게 문서 색인 curl -X PUT "localhost:9200/test/_doc/1" -H 'Content-Type: application/json' -d' { "counter" : 1, "tags" : ["red"] } ' --- 2. 스크립트 업데이트 curl -X POST "localhost:9200/test/_doc/1/_update" -H 'Content-Type: application/json' -d' { "script" : { "source": "ctx._source.counter += params.count", "lang": "painless", "params" : { "count" : 4 } } } ' 또는 curl -X POST "localhost:9200/test/_doc/1/_update" -H 'Content-Type: application/json' -d' { "script" : { "source": "ctx._source.tags.add(params.tag)", "lang": "painless", "params" : { "tag" : "blue" } } } '
- painless: 엘라스틱서치의 스크립팅 표준 언어
update_by_query
쿼리로 매치되는 레코드 집합을 다시 색인한다. delete_by_query 와 비슷하다(?)
curl -X POST "localhost:9200/test/_update_by_query?conflicts=proceed" -H 'Content-Type: application/json' -d' { "query": { "term": { "counter": "5" } } } ' --- { "took": 76, "timed_out": false, "total": 1, "updated": 1, "deleted": 0, "batches": 1, "version_conflicts": 0, "noops": 0, "retries": { "bulk": 0, "search": 0 }, "throttled_millis": 0, "requests_per_second": -1.0, "throttled_until_millis": 0, "failures": [ ] }
document 다중 조회
여러 개의 ID 로 많은 문서를 가져오기 위해 엘라스틱서치는 Multi Get API 를 지원한다. 엘라스틱서치는 내부적으로 여러 GET 작업을 여러 샤드에 병렬로 분산시키고 결과를 수집해서 사용자에게 반환한다.
curl -X GET "localhost:9200/_mget" -H 'Content-Type: application/json' -d' { "docs" : [ { "_index" : "test", "_type" : "_doc", "_id" : "1" }, { "_index" : "test", "_type" : "_doc", "_id" : "2" } ] } '
다음과 같은 필드를 포함할 수 있다.
- _index: 문서가 포함된 색인. URL 로 전달했다면 생략 가능하다.
- _type: 문서 타입. URL 로 전달했다면 생략 가능하다.
- _id: 문서 ID
- stored_fields: (Optional) 검색할 필드 목록
- _source: (Optional) 원폰 필터 객체
- routing: (Optional) 샤드 라우팅 필드. 쿼리 파라미터도 가능
bulk 작업
다량의 문서를 입력/삭제/변경할 때 HTTP 오베허드는 두드러진다. 속도 향상을 위해 엘라스틱서치는 Bulk CRUD 호출을 실행할 수 있다. (\n 개행문자가 꼭!필요하다)
curl -X POST "localhost:9200/_bulk" -H 'Content-Type: application/json' -d' { "index" : { "_index" : "test", "_type" : "_doc", "_id" : "1" } } { "field1" : "value1" } { "delete" : { "_index" : "test", "_type" : "_doc", "_id" : "2" } } { "create" : { "_index" : "test", "_type" : "_doc", "_id" : "3" } } { "field1" : "value3" } { "update" : {"_id" : "1", "_type" : "_doc", "_index" : "test"} } { "doc" : {"field2" : "value2"} } '
index 생성
데이터를 색인하기 전에 첫 작업은 데이터의 주 컨테이너라고 할 수 있는 index 를 만드는 것 index 는 SQL의 데이터베이스 개념, type(table?) 과 document(record?)을 위한 컨테이너다
curl -X PUT "localhost:9200/twitter" -H 'Content-Type: application/json' -d' { "settings" : { "index" : { "number_of_shards" : 3, "number_of_replicas" : 2 } } } ' -- 성공 {"acknowledged":true,"shards_acknowledged":true,"index":"twitter"} -- 실패 (동일 index 가 있는 경우) { "error" : { "root_cause" : [ { "type" : "resource_already_exists_exception", "reason" : "index [twitter/9ImsuIKGQUiqYgMh-Jm2Bw] already exists", "index_uuid" : "9ImsuIKGQUiqYgMh-Jm2Bw", "index" : "twitter" } ], "type" : "resource_already_exists_exception", "reason" : "index [twitter/9ImsuIKGQUiqYgMh-Jm2Bw] already exists", "index_uuid" : "9ImsuIKGQUiqYgMh-Jm2Bw", "index" : "twitter" }, "status" : 400 }
- number_of_shards: index를 작성하는 샤드 개수(각 샤드는 232개의 document 까지 저장 가능)
- number_of_replicas: 복제 개수 (이 값은 1 이상으로 설정하는 것이 좋다)
동작 방식
- primary node 에 처음 index를 생성하며, 클러스터의 모든 node에 그 상태를 전파한다.
- 기본 매핑(빈 매핑)을 작성한다.
- index에 필요한 모든 shard 를 초기화하고 데이터를 수신할 준비를 한다.
index name 제약
아스키 문자 [a-z], 숫자[0-9], 특수기호[., -, &, _]
index 삭제
index 삭제는 index shard, mapping, document 를 삭제한다. 삭제할 때는 관련된 모든 index가 디스크로부터 삭제되서 잃게되며 백업이 따로 없다면 복구할 수 없다. index 명 대신 _all 로 전체 index 를 삭제할 수 있다. 운영 환경에서는 action.destructive_requireds_name:true 로 변경하여 전체 index 삭제를 비활성화하는 것이 좋다.
curl -X DELETE "localhost:9200/twitter" -- 성공 {"acknowledged":true} -- 실패 (index 가 없는 경우) { "error" : { "root_cause" : [ { "type" : "index_not_found_exception", "reason" : "no such index", "resource.type" : "index_or_alias", "resource.id" : "twitter", "index_uuid" : "_na_", "index" : "twitter" } ], "type" : "index_not_found_exception", "reason" : "no such index", "resource.type" : "index_or_alias", "resource.id" : "twitter", "index_uuid" : "_na_", "index" : "twitter" }, "status" : 404 }
index 온/오프라인 변경
데이터를 유지하면서 자원(메모리/CPU)를 절약하려면 index 삭제 대신 닫아두는 것이 좋다. 엘라스틱서치는 index 를 열거나 닫아 온라인이나 오프라인모드로 설정할 수 있다.
curl -X POST "localhost:9200/my_index/_close" curl -X POST "localhost:9200/my_index/_open"
index 를 닫는 경우, 메타데이터 상태 변경을 제외하고 클러스터의 오버헤드가 없다. 또한 index shard 는 꺼지고 파일 디스크립터, 메모리, 스레드는 사용하지 않는다.
index 맵핑 정의
index 에 type mapping을 하는 방법으로 SQL로 치면 테이블 생성정도로 보면된다. index 의 유무를 확인하고 정의된 대로 한개 이상의 매핑을 만든다. 매핑을 위한 삭제 API 는 없다. 매핑을 삭제하거나 변경하려면 새로운 index 를 만들어서 전체레코드를 다시 색인해야한다. 엘라스틱서치에서는 속도향상을 위해 reindex 명령을 제공하고 있다.
curl -X PUT "localhost:9200/twitter" -H 'Content-Type: application/json' -d' {} ' curl -X PUT "localhost:9200/twitter/_mapping/_doc" -H 'Content-Type: application/json' -d' { "properties": { "email": { "type": "keyword" } } } '
index 생성에 _mapping 필드를 정의하면 생성과 함께 타입 매핑을 정의할 수 있다.
curl -X PUT "localhost:9200/test" -H 'Content-Type: application/json' -d' { "settings" : { "number_of_shards" : 1 }, "mappings" : { "_doc" : { "properties" : { "field1" : { "type" : "text" } } } } } '
타입매핑 참고
mapping 조회
index d에 정의된 매핑을 조회한다. 매핑을 클러스터 수준으로 저장한다. 조회 호출은 색인과 타입이 있는지 모두 확인하고 저장된 매핑을 반환한다.
curl -X GET "localhost:9200/_mapping" curl -X GET "localhost:9200/twitter/_mapping" curl -X GET "localhost:9200/twitter/_doc/_mapping"
reindex
5.x 부터 추가된 기능이며, 하나의 index 에서 다른 index로 document를 복사한다. 아래 예제는 twitter 를 new_twitter 로 복사하는 예제이다.
curl -X POST "localhost:9200/_reindex" -H 'Content-Type: application/json' -d' { "source": { "index": "twitter" }, "dest": { "index": "new_twitter" } } '
- 원본 색인의 모든 문서에 대해 _source 를 활성화 해야 한다.
- reindex 는 목적지 색인에 설정을 변경하지 않는다. Reindex 를 실행하기 전에 색인의 설정(매핑, 샤드 개수, 리플리카 등등)을 진행해야 한다.
?refresh
엘라스틱서치는 색인 강제 새로고침을 사용해 검색자의 상태를 제어할 수 있다. 강제하지 않으면 최근 색인된 문서는 일정 시간(일반적으로 1초)이후에야 검색이 가능해 질 것이다.
curl -X PUT "localhost:9200/test/_doc/1?refresh" -H 'Content-Type: application/json' -d' {"test": "test"} '
엘라스틱서치는 파일 디스크립터를 닫았다가 다시 여는 데 필요한 과도한 I/O 로 인한 성능 저하 방지를 위해 문서를 입력할 때마다 매번 색인 상태를 새로 고치지는 않는다. 일반적으로 새로 고침을 호출하는 가장 적절한 때는 많은 데이터를 색인한 바로 다음이다.
타입 매핑
- 디스크의 색인 크기를 줄인다.(사용자 정의 필드를 위한 기능을 비활성화 한다.)
- 관심 필드만 색인한다.(일반적인 속도 향상)
- 빠른 검색이나 실시간 분석을 위한 패싯같은 선행처리한 데이터
- 필드가 다중 토큰으로 분석돼야 하는지, 또는 단일 토큰으로 처리해야 하는지를 올바르게 정의
Core datatypes
- string : text and keyword
- Numeric datatypes : long, integer, short, byte, double, float, half_float, scaled_float
- Date datatype : date
- Boolean datatype : boolean
- Binary datatype : binary
- Range datatypes : integer_range, float_range, long_range, double_range, date_range
mapping parameter
- store: 필드를 별도 색인 조작에 저장해서 조회를 빠르게 한다. 필드 저장은 디스크 공간을 소모하지만, 문서로부터 추출해야 하는 연산(즉, 스크립팅과 집계)을 줄인다. (기본값: false)
- index: 필드를 색인해야 할 때 사용한다. 색이이 되지 않은 필드는 검색이 되지 않는다.
- null_value: 필드가 null일 때 기본값을 지정한다.
- boost: 필드의 중요도를 변경하는데 사용한다. (기본값: 1.0)
- boost 는 term 수준에서만 동작하므로 term, terms, match 쿼리에 주로 사용한다.
- analyzer: 사용할 기본 분석기를 설정한다(기본값: null)
- search_analyzer: 검색 시 사용할 분석기를 지정한다. 지정하지 않으면 부모 객체의 분석기를 사용한다. (기본값: null)
Complex datatypes
- Array datatype : Array support does not require a dedicated type
- Object datatype : object for single JSON objects
- Nested datatype : nested for arrays of JSON objects
Geo datatypes
- Geo-point datatype : geo_point for lat/lon points
- Geo-Shape datatype : geo_shape for complex shapes like polygons
Specialised datatypes
- IP datatype : ip for IPv4 and IPv6 addresses
- Completion datatype : completion to provide auto-complete suggestions
- Token count datatype : token_count to count the number of tokens in a string
- mapper-murmur3 : murmur3 to compute hashes of values at index-time and store them in the index
- mapper-annotated-text : annotated-text to index text containing special markup (typically used for identifying named entities)
- Percolator type : Accepts queries from the query-dsl
- join datatype : Defines parent/child relation for documents within the same index
- Alias datatype : Defines an alias to an existing field.
Multi-fields
It is often useful to index the same field in different ways for different purposes. For instance, a string field could be mapped as a text field for full-text search, and as a keyword field for sorting or aggregations. Alternatively, you could index a text field with the standard analyzer , the english analyzer, and the french analyzer . This is the purpose of multi-fields. Most datatypes support multi-fields via the fields parameter.
참고
- https://www.elastic.co/guide/en/elasticsearch/reference/6.6/indices.html
- https://www.elastic.co/guide/en/elasticsearch/reference/6.6/docs.html
- https://www.elastic.co/guide/en/elasticsearch/reference/6.6/mapping-types.html
- https://www.elastic.co/guide/en/elasticsearch/reference/6.6/mapping-params.html
- http://www.acornpub.co.kr/book/elasticsearch-cookbook-3