tar -zxf 파일명
으로 설치.cd elasticsearch-7.13.2
명령으로 이동 (버전은 다를 수 있음)bin/elasticsearch
명령어로 실행curl http://localhost:9200
{
"name" : "Hwanils-MacBook-Pro.local",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "pNh3CaPDR2SrmAPeYws87g",
"version" : {
"number" : "7.13.2",
"build_flavor" : "default",
"build_type" : "tar",
"build_hash" : "4d960a0733be83dd2543ca018aa4ddc42e956800",
"build_date" : "2021-06-10T21:01:55.251515791Z",
"build_snapshot" : false,
"lucene_version" : "8.8.2",
"minimum_wire_compatibility_version" : "6.8.0",
"minimum_index_compatibility_version" : "6.0.0-beta1"
},
"tagline" : "You Know, for Search"
}
tar -zxf 방금 다운로드받은 파일명
으로 압축 해제 후 해당 디렉토리로 이동bin/kibana
로 실행cluster안에 저장된 each unit of data를 document라고 부른다.
document는 JSON object형태다.
document에 인덱스 과정을 거치면 데이터는 메타데이터를 포함하여 저장된다.
아래 예시에서 보듯이 찐데이터는 _source라는 키값안에 저장된다.
document들은 index를 통해 organize된다.
ES안의 모든 document들은 index안에 저장된다.
index에 엮이는 document 개수에는 LImit가 없다.
an index is therefore a collection of documents that have similar characteristics and are logically related
GET /_cluster/health
로 request를 보낸다.GET /_cat/nodes?v
GET /_cat/indices?v
결과화면
kibana 인덱스를 볼 수 있다. 키바나가 데이터를 ES에 저장하기 때문에 그렇다.
kibana 인덱스 앞에 '.'이 붙어있는 이유는 키비나 인터페이스에서 인덱스를 숨기기 위함이다. linux에서 .파일이 숨김파일인 것과 같은 원리
curl -XGET "http://localhost:9200/_cluster/health"
콘솔
GET /.kibana/_search
{
"query": {
"match_all": {}
}
}
curl -XGET "http://localhost:9200/.kibana/_search" -H 'Content-Type: application/json' -d' { "query": { "match_all": {} } }'
- Sharding is a way to divide indices into smaller pieces
- Each piece is referred to as a shard
- Sharding is done at the index level
- The main purpose is to horizontally scale the data volume
- A shard is an independent index ...kind of
- Each shard is an Apache Lucene index
- An Elasticsearch index consists of one or more Lucene indices
- A shard has no predefined size; it grows as documents are added to it
- A shard may store up to about two billoin documents
- Mainly to be able to store more documents
- To easier fit large indices onto nodes
- Improved performance
- Parallelization of queries increases the throughput of an index
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
green open .kibana_7.13.2_001 08rag9n_TOC4k7D4eQUe-w 1 0 31 24 2.1mb 2.1mb
green open .apm-custom-link dMpoukvrTmiVpwBHe1lj4g 1 0 0 0 208b 208b
green open .kibana-event-log-7.13.2-000001 pWU1ONPESLKbVUcLhK_lAA 1 0 1 0 5.6kb 5.6kb
green open .apm-agent-configuration A-cKaIyMTUejePkKuBNQOg 1 0 0 0 208b 208b
Q: How does Elasticsearch scale the volume of data?
A: By using sharding. Sharding enables us to scale the data volume. Adding more nodes to the cluster helps too, but only to a certain extent (unless there are no very large indices).
Q: What is a shard?
A: A subset(part) of and index' data
PUT /pages
결과
디폴트 세팅이 적용됐기 때문에 shard 1개, replica shard 1개가 생성됐다.
이제 GET /_cluster/health
로 cluster의 health를 체크해보자. status가 green에서 yellow로 바뀐걸 볼 수 있다.
{
"cluster_name" : "elasticsearch",
"status" : "yellow",
"timed_out" : false,
"number_of_nodes" : 1,
"number_of_data_nodes" : 1,
"active_primary_shards" : 7,
"active_shards" : 7,
"relocating_shards" : 0,
"initializing_shards" : 0,
"unassigned_shards" : 1,
"delayed_unassigned_shards" : 0,
"number_of_pending_tasks" : 0,
"number_of_in_flight_fetch" : 0,
"task_max_waiting_in_queue_millis" : 0,
"active_shards_percent_as_number" : 87.5
}
GET /_cat/indices?v
로 index를 봐보자. 방금 만든 pages의 상태가 yellow다. 이유는?
replica 1개가 생성됐는데 노드는 1개 밖에 없어서 할당이 안됐기 때문이다. 현재 replica는 pending상태고, 노드 1개를 더하면 그제서야 생성된다.
인덱스는 잘 작동하지만 노드 하나가 뻑나면 pages인덱스가 down될거기 때문에 yellow 경고를 주는 것이다.
kibana노드들은 replica가 0이다. 이러면 위험한거 아닌가?
대신 kibana는 'auto_expand_replicas' 옵션이 붙어있다.
디폴트 노드가 1개니, 처음엔 replica도 0으로 설정되있다가, node가 2개가 되면 replica도 1개 늘어난다.
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
green open .kibana_7.13.2_001 08rag9n_TOC4k7D4eQUe-w 1 0 33 5 2.1mb 2.1mb
yellow open pages ENzeDkDsSDmAtnkkIT3SDQ 1 1 0 0 208b 208b
green open .apm-custom-link dMpoukvrTmiVpwBHe1lj4g 1 0 0 0 208b 208b
green open .kibana-event-log-7.13.2-000001 pWU1ONPESLKbVUcLhK_lAA 1 0 1 0 5.6kb 5.6kb
green open .apm-agent-configuration A-cKaIyMTUejePkKuBNQOg 1 0 0 0 208b 208b
green open .kibana_task_manager_7.13.2_001 n7IVamyFRIqICjZs3sGgUg 1 0 10 2191 262.6kb 262.6kb
GET /_cat/shards?v
index shard prirep state docs store ip node
.kibana_7.13.2_001 0 p STARTED 33 2.1mb 127.0.0.1 Hwanils-MacBook-Pro.local
.apm-agent-configuration 0 p STARTED 0 208b 127.0.0.1 Hwanils-MacBook-Pro.local
pages 0 p STARTED 0 208b 127.0.0.1 Hwanils-MacBook-Pro.local
pages 0 r UNASSIGNED
.ds-ilm-history-5-2021.07.02-000001 0 p STARTED 127.0.0.1 Hwanils-MacBook-Pro.local
.apm-custom-link 0 p STARTED 0 208b 127.0.0.1 Hwanils-MacBook-Pro.local
.kibana-event-log-7.13.2-000001 0 p STARTED 1 5.6kb 127.0.0.1 Hwanils-MacBook-Pro.local
.kibana_task_manager_7.13.2_001 0 p STARTED 10 350.8kb 127.0.0.1 Hwanils-MacBook-Pro.local
ES를 새로 다운받아 다른 폴더에 넣고 실행시킨다. (그냥 ES 두개를 실행하는 거임)
대신 이때 새로운 ES의 이름을 바꿔줘야 한다. 이름이 중복되면 안됨.
이름은 /config/elasticsearch.yml에서 바꿀 수 있다.
node.name: node-2
이런 식으로 바꿔주면 됨.이때 best practice는 노드가 속할 cluster의 이름도 적어주는 것이다.
GET /_cluster/health
로 조회해보면 노드 2개가 된 것을 볼 수 있다.
"cluster_name" : "elasticsearch",
"status" : "green",
"timed_out" : false,
"number_of_nodes" : 2,
"number_of_data_nodes" : 2,
"active_primary_shards" : 8,
"active_shards" : 16,
"relocating_shards" : 0,
"initializing_shards" : 0,
"unassigned_shards" : 0,
"delayed_unassigned_shards" : 0,
"number_of_pending_tasks" : 0,
"number_of_in_flight_fetch" : 0,
"task_max_waiting_in_queue_millis" : 0,
"active_shards_percent_as_number" : 100.0
}
GET /_cat/shards?v
로 샤드를 조회해보면 샤드들이 primany, replica노드에 고르게 배정됨을 볼 수 있다. 이건 "auto_expand_replicas" 덕분이다.index shard prirep state docs store ip node
.apm-custom-link 0 p STARTED 0 208b 127.0.0.1 Hwanils-MacBook-Pro.local
.apm-custom-link 0 r STARTED 0 208b 127.0.0.1 node-2
.tasks 0 p STARTED 4 27.2kb 127.0.0.1 Hwanils-MacBook-Pro.local
.tasks 0 r STARTED 4 21.2kb 127.0.0.1 node-2
.kibana_task_manager_7.13.2_001 0 p STARTED 10 118.6kb 127.0.0.1 Hwanils-MacBook-Pro.local
.kibana_task_manager_7.13.2_001 0 r STARTED 10 148.1kb 127.0.0.1 node-2
.ds-ilm-history-5-2021.07.02-000001 0 p STARTED 127.0.0.1 Hwanils-MacBook-Pro.local
.ds-ilm-history-5-2021.07.02-000001 0 r STARTED 127.0.0.1 node-2
.kibana-event-log-7.13.2-000001 0 p STARTED 3 16.3kb 127.0.0.1 Hwanils-MacBook-Pro.local
.kibana-event-log-7.13.2-000001 0 r STARTED 3 16.3kb 127.0.0.1 node-2
.apm-agent-configuration 0 p STARTED 0 208b 127.0.0.1 Hwanils-MacBook-Pro.local
.apm-agent-configuration 0 r STARTED 0 208b 127.0.0.1 node-2
.kibana_7.13.2_001 0 p STARTED 39 4.2mb 127.0.0.1 Hwanils-MacBook-Pro.local
.kibana_7.13.2_001 0 r STARTED 39 2.1mb 127.0.0.1 node-2
pages 0 p STARTED 0 208b 127.0.0.1 Hwanils-MacBook-Pro.local
pages 0 r STARTED 0 208b 127.0.0.1 node-2
bin/elasticsearch -Enode.name=node-3
-Epath.data=./node-3/data -Epath.logs=./node-3/logs
이제 위 두 명령어를 합쳐서 터미널에 입력하자. 명령어는 ES의 루트 디렉토리에서 때린다.
bin/elasticsearch -Enode.name=node-3 -Epath.data=./node-3/data -Epath.logs=./node-3/logs
GET /_cluster/health
명령어로 노드가 3개가 됨을 볼 수 있다.{
"cluster_name" : "elasticsearch",
"status" : "green",
"timed_out" : false,
"number_of_nodes" : 3,
"number_of_data_nodes" : 3,
"active_primary_shards" : 8,
"active_shards" : 16,
"relocating_shards" : 1,
"initializing_shards" : 0,
"unassigned_shards" : 0,
"delayed_unassigned_shards" : 0,
"number_of_pending_tasks" : 1,
"number_of_in_flight_fetch" : 0,
"task_max_waiting_in_queue_millis" : 0,
"active_shards_percent_as_number" : 100.0
}
강사 화면을 보면 node.role 값이 dim이다. "data", "ingest", "master"을 뜻한다.
ip heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name
127.0.0.1 31 99 20 2.78 cdfhilmrstw * Hwanils-MacBook-Pro.local
127.0.0.1 42 99 20 2.78 cdfhilmrstw - node-2
127.0.0.1 28 99 20 2.78 cdfhilmrstw - node-3
DELETE /pages
로 위에서 만든 pages 인덱스를 삭제한다.
리턴값은 아래와 같다.
{
"acknowledged" : true
}
PUT /products
로 products라는 인덱스를 생성한다.PUT /products
{
"settings": {
"number_of_shards": 2,
"number_of_replicas": 2
}
}
{
"acknowledged" : true,
"shards_acknowledged" : true,
"index" : "products"
}
POST /products/_doc
{
"name": "Coffe Maker",
"price": 65,
"in_stock": 10
}
{
"_index" : "products",
"_type" : "_doc",
"_id" : "UvRcanoBgN9YOgNagpR5",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 3,
"successful" : 3,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1
}
PUT /products/_doc/100
{
"name": "Toaster",
"price": 60,
"in_stock": 5
}
{
"_index" : "products",
"_type" : "_doc",
"_id" : "100",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 3,
"successful" : 3,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1
}
GET /products/_doc/100
로 아이디가 100인 doc을 조회한다.{
"_index" : "products",
"_type" : "_doc",
"_id" : "100",
"_version" : 1,
"_seq_no" : 0,
"_primary_term" : 1,
"found" : true,
"_source" : {
"name" : "Toaster",
"price" : 60,
"in_stock" : 5
}
}
GET /products/_doc/101
{
"_index" : "products",
"_type" : "_doc",
"_id" : "101",
"found" : false
}
POST /products/_update/100
{
"doc": {
"in_stock": 1,
"tags": ["electronics"]
}
}
{
"_index" : "products",
"_type" : "_doc",
"_id" : "100",
"_version" : 4,
"result" : "updated",
"_shards" : {
"total" : 3,
"successful" : 3,
"failed" : 0
},
"_seq_no" : 3,
"_primary_term" : 1
}
GET을 조회해보면 데이터 변경을 확인할 수 있다.
POST /products/_update/100
{
"doc": {
}
}
{
"_index" : "products",
"_type" : "_doc",
"_id" : "100",
"_version" : 1,
"result" : "noop",
"_shards" : {
"total" : 0,
"successful" : 0,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1
}
POST /products/_update/100
{
"script": {
"source": "ctx._source.in_stock--"
}
}
-결과문은 아래와 같다.
{
"_index" : "products",
"_type" : "_doc",
"_id" : "100",
"_version" : 5,
"result" : "updated",
"_shards" : {
"total" : 3,
"successful" : 3,
"failed" : 0
},
"_seq_no" : 4,
"_primary_term" : 1
}
POST /products/_update/100
{
"script": {
"source": "ctx._source.in_stock = 10"
}
}
POST /products/_update/100
{
"script": {
"source": "ctx._source.in_stock -= params.quantity",
"params": {
"quantity": 5
}
}
}
script 업데이트의 result는 항상 "updated"다. non script update는 실제 값이 변경되야 "updated"로 리턴되지만, script는 값 변경 여부와 상관없이 result가 updated다.
아래 세 케이스를 보자.
case 1. 아래는 in_stock이 0일 경우는 result를 noop으로 뱉어달라는 script
POST /products/_update/100
{
"script": {
"source": """
if (ctx._source.in_stock == 0) {
ctx.op = 'noop';
}
ctx._source.in_stock--;
"""
}
}
POST /products/_update/100
{
"script": {
"source": """
if (ctx._source.in_stock > 0) {
ctx._source.in_stock--;
}
"""
}
}
POST /products/_update/100
{
"script": {
"source": """
if (ctx._source.in_stock <= 1) {
ctx.op = 'delete';
}
ctx._source.in_stock--;
"""
}
}
POST /products/_update/101
{
"script": {
"source": "ctx._source.in_stock++"
},
"upsert": {
"name": "TV",
"price": "500",
"in_stock": 5
}
}
{
"_index" : "products",
"_type" : "_doc",
"_id" : "101",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 3,
"successful" : 3,
"failed" : 0
},
"_seq_no" : 31,
"_primary_term" : 1
}
이제 다시 똑같은 upsert 쿼리문을 쳐보자. result는 updated이고, in_stock은 6이 되었다.
GET /products/_doc/101
으로 확인했을 때 아래와 같은 데이터가 있다.
{
"_index" : "products",
"_type" : "_doc",
"_id" : "101",
"_version" : 2,
"_seq_no" : 32,
"_primary_term" : 1,
"found" : true,
"_source" : {
"name" : "TV",
"price" : "500",
"in_stock" : 6
}
}
PUT /products/_doc/101
{
"name" : "TV",
"in_stock" : 10
}
{
"_index" : "products",
"_type" : "_doc",
"_id" : "101",
"_version" : 4,
"_seq_no" : 34,
"_primary_term" : 3,
"found" : true,
"_source" : {
"name" : "TV",
"in_stock" : 10
}
}
DELETE /products/_doc/101
shard_num = hash(_routing) % num_primary_shards
{
"_index" : "products",
"_type" : "_doc",
"_id" : "101",
"_version" : 4,
"_seq_no" : 34,
"_primary_term" : 3,
"found" : true,
"_source" : {
"name" : "TV",
"in_stock" : 10
}
}
shard_num = hash(_routing) % num_primary_shards
이 공식에 shard수가 쓰이기 때문이다.이번 설명은 도큐먼트 하나를 찾는 것에 관한 설명이지, search queries자체가 어떻게 동작하는지에 관한 것은 아니다.
처음으로 특정 노드가 read request를 받는다.
이 노드 is responsible for coordinating the request. coordinating node라 불린다.
이 노드의 첫 역할은 찾고자 하는 document가 어디에 있는지 알아내는 것이다.
이건 라우팅을 통해 이뤄진다.
좀 더 복잡한 설명이 있긴한데 for now, just know that ES tries to select the shard copy that it believes can yield the best performance.
Once a shard has been selected, the coordinating node sends the read request to that shard.
When the shard responds, the coordinating node collects the response and sneds it to the client
POST /products/_update_100?version=1
POST /products/_update/100?if_primary_term=1&if_seq_no=71
doc하나 업데이트 하는건 이미 배웠다.
여러개 doc 업데이트 하는 법 알아보자.
SQL의 UPDATE문과 비슷하다.
세가지 개념이 사용된다.
아래 쿼리문은 products인덱스에 속한 모든 doc들의 in_stock을 1 감소시킨다.
POST /products/_update_by_query
{
"script": {
"source": "ctx._source.in_stock--"
},
"query": {
"match_all": {}
}
}
{
"took" : 272,
"timed_out" : false,
"total" : 2,
"updated" : 2,
"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" : [ ]
}
"conflicts": "proceed"
를 명시해주면 된다.POST /products/_update_by_query
{
"conflicts": "proceed",
"script": {
"source": "ctx._source.in_stock--"
},
"query": {
"match_all": {}
}
}
POST /products/_delete_by_query
{
"query": {
"match_all": {}
}
}
{
"took" : 158,
"timed_out" : false,
"total" : 2,
"deleted" : 2,
"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" : [ ]
}
POST /_bulk
{"index": {"_index": "products", "_id": 200}}
{"name": "Espresso Machine", "price": 199, "in_stock": 5}
{"create": {"_index": "products", "_id": 201}}
{"name": "Milk Frother", "price": 149, "in_stock": 14}
{
"took" : 87,
"errors" : false,
"items" : [
{
"index" : {
"_index" : "products",
"_type" : "_doc",
"_id" : "200",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 3,
"successful" : 2,
"failed" : 0
},
"_seq_no" : 3,
"_primary_term" : 3,
"status" : 201
}
},
{
"create" : {
"_index" : "products",
"_type" : "_doc",
"_id" : "201",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 3,
"successful" : 2,
"failed" : 0
},
"_seq_no" : 4,
"_primary_term" : 3,
"status" : 201
}
}
]
}
GET /products/_search
{
"query": {
"match_all": {}
}
}
{
"took" : 171,
"timed_out" : false,
"_shards" : {
"total" : 2,
"successful" : 2,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 2,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "products",
"_type" : "_doc",
"_id" : "200",
"_score" : 1.0,
"_source" : {
"name" : "Espresso Machine",
"price" : 199,
"in_stock" : 5
}
},
{
"_index" : "products",
"_type" : "_doc",
"_id" : "201",
"_score" : 1.0,
"_source" : {
"name" : "Milk Frother",
"price" : 149,
"in_stock" : 14
}
}
]
}
}
POST /_bulk
{"update": {"_index": "products", "_id": 201} }
{"doc": {"price": 129 } }
{"delete": {"_index": "products", "_id": 200} }
POST /products/_bulk
{"update": {"_id": 201} }
{"doc": {"price": 129 } }
{"delete": {"_id": 200} }
{
"took" : 86,
"errors" : false,
"items" : [
{
"update" : {
"_index" : "products",
"_type" : "_doc",
"_id" : "201",
"_version" : 2,
"result" : "updated",
"_shards" : {
"total" : 3,
"successful" : 2,
"failed" : 0
},
"_seq_no" : 5,
"_primary_term" : 3,
"status" : 200
}
},
{
"delete" : {
"_index" : "products",
"_type" : "_doc",
"_id" : "200",
"_version" : 2,
"result" : "deleted",
"_shards" : {
"total" : 3,
"successful" : 2,
"failed" : 0
},
"_seq_no" : 6,
"_primary_term" : 3,
"status" : 200
}
}
]
}
Content-Type: application/x-ndjson
으로 해야한다.application/json
도 되긴 하는데, 정석은 아니다.curl -H "Content-Type: application/x-ndjson" -XPOST http://localhost:9200/products/_bulk --data-binary "@products-bulk.json"
출처: udemy Bo Andersen의 Complete Guide to Elasticsearch 강의.
https://www.udemy.com/course/elasticsearch-complete-guide/learn/lecture/7585356#overview