api specification 좀 깔끔히 정리해주면 덧나나. 정말로 찾기가 힘들다고 회사에서 툴툴댔는데 7 버전으로 올라오면서 좀 나아지긴 했다.
여기 있는 API에 익숙해지면 버전이 변경되어도 어디를 찾아야할지 대충 감이 오기 때문에 일단 한 버전에 익숙해지도록 노력해보자...
그리고 이전 버전 ELK를 사용한다고 해서 문제가 될 건 없지만 기술 지원은 받을 수 없다는 것을 알아두자.
상당히 빠르게 버전업되고, 이에 따라 기술 지원을 포기하게 되는 버전이 생각보다 높다.
https://www.elastic.co/kr/support/eol
Cluster APIs
https://www.elastic.co/guide/en/elasticsearch/reference/7.10/cluster.html
cluster health api
https://www.elastic.co/guide/en/elasticsearch/reference/7.10/cluster-health.html
GET /_cluster/health/<target>
node stats api
https://www.elastic.co/guide/en/elasticsearch/reference/7.10/cluster-nodes-stats.html
GET /_nodes/stats
GET /_nodes/<node_id>/stats // <node_id> Comma-separated list of node IDs or names
node info API
GET /_nodes
index APIs(과거명 : indicies APIs)
https://www.elastic.co/guide/en/elasticsearch/reference/7.10/indices.html
* 참고로 논리적인 document의 구분은 indicies, document를 저장하는 행위는 indexing이라고 합니다.
우리는 index를 생성한 다음 해당 index에 document를 넣는 indexing(색인) 작업을 할 것입니다.
작업순서로 보면 index(indicies)생성 -> document를 특정 index에 저장(indexing)
create index
https://www.elastic.co/guide/en/elasticsearch/reference/7.10/indices-create-index.html
PUT /<index>
delete index
https://www.elastic.co/guide/en/elasticsearch/reference/7.10/indices-delete-index.html
* 만약, 지우지 않고, 같은 이름의 index이되 새로운 데이터셋을 넣고 싶다면, index pattern 자체를 지워야 한다. kibana - stack manager - index patterns - delete 로!
DELETE /<index>
get mapping
https://www.elastic.co/guide/en/elasticsearch/reference/7.10/indices-get-mapping.html
GET /<target>/_mapping
Document APIs
https://www.elastic.co/guide/en/elasticsearch/reference/7.10/docs.html#docs
* Document APIs 내부에 다양한 api들이 존재하는데, Index api, delete api와 같이 단순히 document를 CRUD하는 api부터 bulk api 등 multi-document를 다루는 api도 존재함.
index api
https://www.elastic.co/guide/en/elasticsearch/reference/7.10/docs-index_.html
* 당연하겠지만 여기서의 index는 indexing, 즉, document 저장을 의미한다.
* 만약, indexing하고자 하는 데이터가 고유한 id를 이미 가지고 있는 경우 식별자 필드를 그대로 id로 넣어주는 것이 편리하다! 즉, DB Record의 식별자 키를 elasticSearch의 실제 키로 사용하는 것이 좋다는 말이다.
* id를 직접 부여할 경우 PUT 메서드, 자동 id 부여는 POST 메서드를 사용한다.
* 같은 id를 가진 document를 PUT하게 되면 오류가 발생하는 것이 아니라 기존 document는 overwritten되는 방식으로 update 되며, 결과값 필드 중 _version이 올라가는 것을 확인할 수 있다.
* 생성, 수정, 삭제시 해당 id의 _version이 올라간다. 자세한 내용은 versioning
* document가 바뀌지 않더라도 언제나 새로운 버전의 document가 생성된다. 자세한 내용은 noop update
PUT /<target>/_doc/<_id> // natural_identifier가 존재한다면 이 녀석을 id로 설정하자
POST /<target>/_doc/ // Automatic ID generation. natural_identifier가 없는 경우 편함
만약 indexing하는 과정 중 기존에 존재하는 id가 같아 document를 overwrite하고 싶지 않다면, operation type을 create로 명시해주면 된다. 이것도 elasticSearch 버전마다 표기법이 달라져서 쬐끔 번거로운 면이 있다.
_create guarantees that the document is only indexed if it does not already exist. - https://www.elastic.co/guide/en/elasticsearch/reference/7.10/docs-index_.html#docs-index-api-desc
만약, 해당 id에 이미 도큐먼트가 존재한다면 version_conflict_engine_exception 에러를 발생시킨다.
PUT /<target>/_create/<_id>
POST /<target>/_create/<_id>
get api
https://www.elastic.co/guide/en/elasticsearch/reference/7.10/docs-get.html
* CRUD로 치면 Read에 해당하는 부분이다.
GET <index>/_doc/<_id>
update api
https://www.elastic.co/guide/en/elasticsearch/reference/7.10/docs-update.html
// update_part_of_a_document. 즉, 추가적인 부분만 업데이트 되지, overwrite하는 것이 아님.
POST /<index>/_update/<_id>
{
"doc": { ... }
}
delete api
https://www.elastic.co/guide/en/elasticsearch/reference/7.10/docs-delete.html
DELETE /<index>/_doc/<_id>
reindex api
https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-reindex.html
* mapping을 수정하기 위해 사용된다. mapping을 수정하는 것은 불가능하기 때문에 새로운 mapping을 가진 index를 새로 만들어서 재색인 작업을 해야하는데, 이 작업에 reindex api 빡!
* https://yookeun.github.io/elasticsearch/2018/12/28/elastic-reindex/ 개인 블로그인데 정리 잘 되어 있다. ㅎ
POST _reindex
{
"source": {
"index": "my-index-000001"
},
"dest": {
"index": "my-new-index-000001"
}
}
bulk api
https://www.elastic.co/guide/en/elasticsearch/reference/7.10/docs-bulk.html
POST _bulk
{ "index" : { "_index" : "test", "_id" : "1" } }
{ "field1" : "value1" }
{ "delete" : { "_index" : "test", "_id" : "2" } }
{ "create" : { "_index" : "test", "_id" : "3" } }
{ "field1" : "value3" }
{ "update" : {"_id" : "1", "_index" : "test"} }
{ "doc" : {"field2" : "value2"} }
Search APIs
https://www.elastic.co/guide/en/elasticsearch/reference/7.10/search.html
search api
https://www.elastic.co/guide/en/elasticsearch/reference/7.10/search-search.html
* 순수하게 search api만 사용되는 것이 아니라 query DSL이라던가, aggregation과 함께 사용됩니다!
기본적으로 size가 10이니까 쿼리 결과물로 10개만 반환되었다고 당황 ㄴㄴ
GET /<target>/_search
GET /_search
POST /<target>/_search
POST /_search
또한, 반환값중 total 값도 최대 10000개까지만 반환됨. => "total" : { "value" : 10000, "relation" : "gte" },
만약 정확한 최대 갯수를 알고 싶다면 track_total_hits를 true로 설정해두자.
GET <target>/_search
{
"track_total_hits": true
}
query DSL을 활용하여 결과값을 받을 수도 있다. 여기서는 range를 사용해보았다.
https://www.elastic.co/guide/en/elasticsearch/reference/7.10/query-dsl.html
* range외에도 매우 다양한 query field들이 존재합니다.
* compound query도 존재합니다. query DSL은 내용이 꽤나 방대하기 때문에 별도의 글에서 다룰 것입니다.
GET news_headlines/_search
{
"query": {
"range": {
"date": {
"gte": "2015-06-20",
"lte": "2015-09-22"
}
}
}
}
* match의 경우 operator 기본값이 OR이기에 띄어쓰기마다 단어가 존재하면 일치로 본다. 예를 들어 capital of korea면 capital, of, korea 세 단어 중 하나만 존재해도 일치로 본다. OR 연산을 할 경우 Recall(재현율)이 높아지는 결과를 가져오겠죠. 다만 Precision-Recall Trade-off 법칙에 의해 Precision(정밀도)가 떨어질 수 있다는 단점이 있습니다.
* 반대로 match의 operator를 AND로 설정한다면, Precision이 높아지지만 Recall이 낮아집니다.
* OR이나 AND가 각각 너무 극단적이라면 minimum_should_match를 설정해볼 수 있습니다.
GET news_headlines/_search
{
"query": {
"match": {
"headline": {
"query": "Khloe Kardashian Kendall Jenner",
"operator": "and" // AND 연산을하여 precision은 높아지고, recall이 낮아짐
}
}
}
}
GET news_headlines/_search
{
"query": {
"match": {
"headline": {
"query": "Khloe Kardashian Kendall Jenner",
"minimum_should_match": 3 // OR 연산을 하되 3개 이상 매칭되어야 함
}
}
}
}
Aggregation과 함께 쓰일 수도 있다!
https://www.elastic.co/guide/en/elasticsearch/reference/7.10/search-aggregations.html
You can run aggregations as part of a search by specifying the search API's aggs parameter!
여기서는 term aggregation을 사용했습니다.
GET news_headlines/_search
{
"aggs": {
// my-agg-name라는 필드명으로, category 별로 종합하길 원함
"my-agg-name": {
"terms": {
"field": "category",
"size": 100
}
}
}
}
결과값은 아래와 같습니다.
... hits 생략
"aggregations" : {
"my-agg-name" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "POLITICS",
"doc_count" : 32739
},
{
"key" : "WELLNESS",
"doc_count" : 17827
},
{
"key" : "ENTERTAINMENT",
"doc_count" : 16058
},
...
query DSL과 Aggregation을 함께 사용할 수도 있다. (여기서는 significant_text aggregation을 사용하였다.)
아래 쿼리가 요구하는 바는, "category 필드가 ENTERTAINMENT인 도큐먼트를 가져오되, 그 안에서 significant_text aggregation을 적용하여 popular_in_etnertainment라는 이름으로 반환하라"입니다. 다른 건 몰라도, "쿼리 결과 내에서 aggregation을 한다"라고 알아두면 되겠습니다.
GET news_headlines/_search
{
"query": {
"match": {
"category": "ENTERTAINMENT"
}
},
"aggregations": {
"popular_in_entertainment": {
"significant_text": {
"field": "headline"
}
}
}
}
대략적으로 쿼리 결과물은 아래와 같이 나오겠죠.
{
"took" : 29,
"timed_out" : false,
"_shards" : {...},
"hits" : {
"total" : {
"value" : 10000,
"relation" : "gte"
},
"max_score" : 1.0,
"hits" : [...]
},
"aggregations" : {
"my-agg-name" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [...]
}
}
}