https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-threadpool.html



Thread pool typesedit

The following are the types of thread pools and their respective parameters:

fixededit

The fixed thread pool holds a fixed size of threads to handle the requests with a queue (optionally bounded) for pending requests that have no threads to service them.

The size parameter controls the number of threads, and defaults to the number of cores times 5.

The queue_size allows to control the size of the queue of pending requests that have no threads to execute them. By default, it is set to -1 which means its unbounded. When a request comes in and the queue is full, it will abort the request.

thread_pool:
    index:
        size: 30
        queue_size: 1000

scalingedit

The scaling thread pool holds a dynamic number of threads. This number is proportional to the workload and varies between the value of the core and max parameters.

The keep_alive parameter determines how long a thread should be kept around in the thread pool without it doing any work.

thread_pool:
    warmer:
        core: 1
        max: 8
        keep_alive: 2m


Posted by '김용환'
,


elasticsearch에 실수로 long time 쿼리를 실행했지만... 요청을 더 이상 실행하고 싶지 않다면, 재시작을 하는 것이 좋다. 다. 





만약 elasticsearch 2.x 이상의 버전을 사용하고 있다면..다음을 참조한다. 


https://www.elastic.co/guide/en/elasticsearch/reference/current/tasks.html



GET _tasks 호출 후, 해당 task_id를 찾은 후 POST _tasks/node_id:task_id/_cancel를 호출한다..


Posted by '김용환'
,



elasticsearch의 쓰레드 상태를 보려면 다음과 같은 _cat/thread_pool 를 본다. 


$ curl -s http://abc.google.com:9200/_cat/thread_pool


abc.google.com           bulk                 7  0  784202

abc.google.com           fetch_shard_started  0  0       0

abc.google.com           fetch_shard_store    0  0       0

abc.google.com           flush                0  0       0

abc.google.com           force_merge          0  0       0

abc.google.com           generic              0  0       0

abc.google.com           get                  0  0       0





3,4,5번째 컬럼은 active, queue, rejected를 의미한다. 


bulk api thread가 더이상 요청을 받지 못해 rejected 된 현황을 보여준다. 

Posted by '김용환'
,

일래스틱서치에 필드 캐시의 expire를 설정하는 옵션(indices.fielddata.cache.expire )이 1.x 버전에 있었지만 2.0부터는 사라졌다.



https://www.elastic.co/guide/en/elasticsearch/reference/1.4/index-modules-fielddata.html



indices.fielddata.cache.expire

[experimentalThis functionality is experimental and may be changed or removed completely in a future release. Elastic will take a best effort approach to fix any issues, but experimental features are not subject to the support SLA of official GA features.A time based setting that expires field data after a certain time of inactivity. Defaults to -1. For example, can be set to 5m for a 5 minute expiry.


이 기능이 gc를 많이 유발하고 crash를 일으키는 이슈가 있어서 사라진 듯 하다..

 https://discuss.elastic.co/t/indices-fielddata-cache-expire/1183



1.4에서는 잘 사용해서 문제가 없었지만. 결국 사라진 것으로 봐서는 큰 gc 이슈를 일으킨 것으로 보인다..

어차피 2.0에서 사라졌으니.. 히스토리를 위해서 남겨둔다.




Posted by '김용환'
,




elasticsearch 1.x의 메모리 구조이다.  정말 잘 설명되어 있는 이미지가 있어서 펌한다.



https://kupczynski.info/2015/04/06/fielddata.html



좀 더 크게 보면 다음과 같다.




Posted by '김용환'
,




핫 스레드 API는 여러 정보를 포함한 형태를 가진 텍스트로 리턴한다. 즉 JSON 구조로 리턴하지 않는 형태를 갖고 있다. 


응답 구조 자체에 대해 설명하기 전에 핫 스레드 API의 응답을 생성하는 로직을 짧게 소개한다.


일래스틱서치는 먼저 실행 중인 모든 스레드를 얻은 후 각 스레드에서 소비한 CPU 시간, 특정 스레드가 차단되었거나 대기 상태에 있었던 횟수, 차단된 시간 또는 대기 상태에 있었던 시간 등에 대한 다양한 정보를 수집한다. 


다음에는 특정 시간(interval 매개 변수로 지정) 동안 기다린 후 시간이 지나면 동일한 정보를 다시 수집한다.


이 작업이 완료되면 각 특정 스레드가 실행되고 있는 시간에 따라 스레드가 정렬된다. 가장 오랜 기간 실행 중인 스레드가 목록 맨 위에 오도록 내림차순으로 정렬된다.



(이전에 언급된 시간은 type 매개 변수에 지정된 오퍼레이션 타입을 기반으로 측정된다. )


그 다음 일래스틱서치는 첫 번째 N개의 스레드(N은 threads 매개 변수로 지정된 스레드 개수)를 분석한다. 


일래스틱서치는 몇 밀리 초마다 이전 단계에서 선택한 스레드의 스택 트레이스(stack trace)의 일부 스냅샷(스냅 샷 수는 스냅 샷 매개 변수로 지정)을 사용한다. 


마지막으로 해야 할 일은 스레드 상태의 변경을 시각화하고, 호출 함수에게 응답을 리턴하기 위해 스택 트레이스를 그룹핑하는 것이다.




threads 개수는 기본 3개이고 간격은 500ms이며 type의 기본 값은 cpu이다. 

간단한 예제를 보면 다음과 같다.

$ curl 'localhost:9200/_nodes/hot_threads?type=wait&interval=1s'
::: {5OEGj_a}{5OEGj_avT8un0nOak28qQg}{DAzM0ktKQNS047ggd9nYZQ}{127.0.0.1}{127.0.0.1:9300}
   Hot threads at 2017-07-31T11:04:59.943Z, interval=1s, busiestThreads=3, ignoreIdleThreads=true:

    8.4% (35.1ms out of 1000ms) cpu usage by thread 'elasticsearch[kemi][search][T#2]'
     10/10 snapshots sharing following 8 elements
       sun.misc.Unsafe.park(Native Method)
       java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
       java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
       java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:997)
       java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1304)
       java.util.concurrent.CountDownLatch.await(CountDownLatch.java:231)
       org.elasticsearch.bootstrap.Bootstrap$1.run(Bootstrap.java:84)
       java.lang.Thread.run(Thread.java:745)

....



결과의 첫 부분을 보면..


핫 스레드 API 정보를 리턴하는 노드가 어느 노드인지 쉽게 알 수 있고 핫 스레드 API 호출이 언제 많은 노드로 전달되는 시점을 알 수 있다.





두 번째 부분은 


8.4% (35.1ms out of 1000ms) cpu usage by thread 'elasticsearch[kemi][search][T#2]'


해당 스레드는 측정이 완료된 시점의 모든 CPU 시간 중 8.4%를 차지함을 알 수 있다. 

cpu usage 부분은 cpu와 동일한 type을 사용하고 있음을 나타낸다 (여기에서 예상할 수 있는 다른 값은 블럭(block) 상태에 있는 스레드의 블럭 사용량(block usage)와 대기 상태에 있는 스레드의 대기 사용량(wait usage)이다).  스레드 이름은 여기에서 매우 중요하다. 

스레드를 살펴보면 해당 일래스틱서치 스레드가 가장 핫한 스레드임을 알 수 있다. 이 예제의 핫 스레드가 모두 검색(search 값)이라는 것을 알 수 있다. 

볼 수 있는 다른 값으로는 recovery_stream(복구 모듈 이벤트), cache(이벤트 캐시), merge(세그먼트 병합), index(데이터 저장 스레드) 등이 있다.



관련 내용은 다음 코드를 확인한다.


https://github.com/elastic/elasticsearch/blob/v5.2.1/core/src/main/java/org/elasticsearch/action/admin/cluster/node/hotthreads/NodesHotThreadsRequest.java



public class NodesHotThreadsRequest extends BaseNodesRequest<NodesHotThreadsRequest> {


    int threads = 3;

    String type = "cpu";

    TimeValue interval = new TimeValue(500, TimeUnit.MILLISECONDS);

    int snapshots = 10;

    boolean ignoreIdleThreads = true;


    // for serialization

    public NodesHotThreadsRequest() {


    }


    /**

     * Get hot threads from nodes based on the nodes ids specified. If none are passed, hot

     * threads for all nodes is used.

     */

    public NodesHotThreadsRequest(String... nodesIds) {

        super(nodesIds);

    }


    public int threads() {

        return this.threads;

    }


    public NodesHotThreadsRequest threads(int threads) {

        this.threads = threads;

        return this;

    }


    public boolean ignoreIdleThreads() {

        return this.ignoreIdleThreads;

    }


    public NodesHotThreadsRequest ignoreIdleThreads(boolean ignoreIdleThreads) {

        this.ignoreIdleThreads = ignoreIdleThreads;

        return this;

    }


    public NodesHotThreadsRequest type(String type) {

        this.type = type;

        return this;

    }


    public String type() {

        return this.type;

    }


    public NodesHotThreadsRequest interval(TimeValue interval) {

        this.interval = interval;

        return this;

    }


    public TimeValue interval() {

        return this.interval;

    }


    public int snapshots() {

        return this.snapshots;

    }


    public NodesHotThreadsRequest snapshots(int snapshots) {

        this.snapshots = snapshots;

        return this;

    }


    @Override

    public void readFrom(StreamInput in) throws IOException {

        super.readFrom(in);

        threads = in.readInt();

        ignoreIdleThreads = in.readBoolean();

        type = in.readString();

        interval = new TimeValue(in);

        snapshots = in.readInt();

    }


    @Override

    public void writeTo(StreamOutput out) throws IOException {

        super.writeTo(out);

        out.writeInt(threads);

        out.writeBoolean(ignoreIdleThreads);

        out.writeString(type);

        interval.writeTo(out);

        out.writeInt(snapshots);

    }

}


Posted by '김용환'
,




루씬 6.0이전의 기본 유사도 모델은 TF-IDF 모델이었지만 루씬 6.0이후의 기본 유사도 모델은 BM25로 변경되었다.


일래스틱서치 5.0부터 루씬 6.0을 사용하면서 기본 유사도 모델이 BM25로 변경되었다. 



BM25 외에 사용할 수 있는 다른 유사도 모델은 다음과 같다.



* TF-IDF(기존 방식) : TF-IDF 모델을 기반으로 하고 일래스틱서치 5.0 이전 버전의 기본 유사도 모델로 사용되었다. 일래스틱서치에 해당 유사도 모델을 사용하려면 classic 이름을 사용해야 한다.



* DFR(divergence from randomness) : 동일 이름의 확률적 모델을 기반으로 한다. 일래스틱서치에서 해당 유사도 모델을 사용하려면 DFR 이름을 사용해야 한다. 랜덤 유사성 모델로부터 나온 디버전스는 자연어 텍스트와 비슷한 데이터에서도 잘 동작한다고 알려져 있다.



* DFI(Divergence from independence) :  동일한 이름의 확률적 모델을 기반으로 한다. 일래스틱서치에서 해당 유사도를 사용하려면 DFI 이름을 사용해야 한다. 

참조

http://trec.nist.gov/pubs/trec21/papers/irra.web.nb.pdf



* IB(Information-based) : DFR에서 사용되는 모델과 매우 유사한다. 해당 유사도를 일래스틱서치에서 사용하려면 IB 이름을 사용해야 한다. DFR 유사도과 마찬가지로 정보 기반 모델은 자연어 텍스트와 비슷한 데이터에서 잘 수행된다고 알려져 있다.



* LM Dirichlet : Bayesian 스무딩과 Dirichlet 사전을 사용한다. 해당 유사도 모델을 사용하려면 LM Dirichlet 이름을 사용해야 한다. 

참조 

https://lucene.apache.org/core/6_2_0/core/org/apache/lucene/search/similarities/LMDirichletSimilarity.html




* LM Jelinek Mercer : Jelinek Mercer 스무딩 방법을 기반으로 한다. 해당 유사도를 사용하려면 LMJelinekMercer 이름을 사용해야 한다. 

참조https://lucene.apache.org/core/6_2_0/core/org/apache/lucene/search/similarities/LMJelinekMercerSimilarity.html







일래스틱서치에서는 유사도 모델과  관련 매개배수를 사용해 매핑할 때 유사도 모델을 설정할 수 있다.


https://www.elastic.co/guide/en/elasticsearch/reference/current/index-modules-similarity.html



예)


* IB 모델


"similarity" : { 

  "esserverbook_ib_similarity" : { 

    "type" : "IB", 

    "distribution" : "ll", 

    "lambda" : "df", 

    "normalization" : "z", 

    "normalization.z.z" : "0.25" 

  } 



*  LM Dirichlet 모델


"similarity" : { 

  "esserverbook_lm_dirichlet_similarity" : { 

    "type" : "LMDirichlet", 

    "mu" : "1000" 

  } 




* LM Jelinek Mercer 모델


"similarity" : { 

  "esserverbook_lm_jelinek_mercer_similarity" : { 

    "type" : "LMJelinekMercer", 

    "lambda" : "0.7" 

  } 



Posted by '김용환'
,



일래스틱서치의 phrase 쿼리에 사용할 수 있는 3가지 스무딩 모델에 대한 설명이다. 어려워서 정리해놨다.. 



아래 일래스틱서치 문서를 보면 관련 내용이 잠깐 나온다. 


https://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters-phrase.html#_smoothing_models


Smoothing Modelsedit

The phrase suggester supports multiple smoothing models to balance weight between infrequent grams (grams (shingles) are not existing in the index) and frequent grams (appear at least once in the index).

stupid_backoff

a simple backoff model that backs off to lower order n-gram models
if the higher order count is
 0 and discounts the lower order n-gram model by a constant factor. The default discount is 0.4. Stupid Backoff is the default model.

laplace

a smoothing model that uses an additive smoothing where a constant
(typically
 1.0 or smaller) is added to all counts to balance weights, The default alpha is 0.5.

linear_interpolation

a smoothing model that takes the weighted mean of the unigrams,
bigrams and trigrams based on user supplied weights (lambdas).
Linear Interpolation doesn’t have any default values. All parameters (
trigram_lambda, bigram_lambda, unigram_lambda) must be supplied.





stupid backoff는 일래스틱서치의 phrase 제안자에서 사용되는 기본 스무딩 모델이다. 해당 스무딩 모델을 변경하거나 강제로 사용하려면 stupid_backoff라는 이름을 사용해야 한다. stupid backoff 스무딩 모델은 더 높은 차수의 n-gram 개수가 0이면 낮은 차수의 n-gram을 사용하는 구현이다(그리고 stupid_backoff는 discount 속성의 값과 동일한 할인을 제공한다). 예제를 설명하기 위해 일반적이고 제안자가 사용하는 인덱스에 존재하는 ab 바이그램(bigram)과 c 유니그램(unigram)을 사용한다고 가정한다. 그러나 abc 트라이그램(trigram)는 갖고 있지 않다. stupid backoff은 abc가 존재하지 않기 때문에 ab 바이그램을 사용할 것이고 물론 ab 바이그램 모델은 discount 속성의 값과 동일한 할인을 받게 될 것이다.



stupid backoff 모델은 discount 속성이라는 변경할 수 있는 단일 속성을 제공한다. 기본적으로 discount 값은 0.4로 설정되어 있고, 낮은 차수의 n-gram 모델의 discount 인자로 사용된다.

n-gram 스무딩 모델에 대한 자세한 내용은 http://en.wikipedia.org/wiki/N-gram#Smoothing_techniques와 http://en.wikipedia.org/wiki/Katz's_back-off_model(설명한 stupid backoff 모델과 비슷하다)을 통해 더 살펴볼 수 있다.



라플라스(laplace)는 부가적인 스무딩 모델이라 불린다. 라플라스가 사용될 때(라플라스를 사용하려면 laplace 값을 사용해야 한다), alpha 매개 변수의 값과 동일한 상수값(기본값은 0.5 이다)은 빈번하고 자주 발생하지 않는 가중치의 균형을 유지하기 위해 개수에 추가된다. 언급한 것처럼 라플라스는 기본값이 0.5인 alpha 매개 변수를 사용해 설정할 수 있다. 일반적으로 alpha 매개 변수의 일반적인 값은 1.0이하이다.

부가적 스무딩에 대한 자세한 내용은 http://en.wikipedia.org/wiki/Additive_smoothing을 참조한다.



Posted by '김용환'
,

일래스틱서치 블로그에서 일래스틱서치 5.0의 집계 기능 향상한 내용을 공유한다. 



출처 : https://www.elastic.co/blog/the-great-query-refactoring-thou-shalt-only-parse-once









https://github.com/elastic/elasticsearch/issues/10217





집계는 일래스틱서치 초기 버전부터 매우 비쌌고, 가장 많은 메모리를 소비했었다. 일래스틱서치 1.4에서는 샤드 쿼리 캐시(shard query cache)라고 하는 새로운 기능이 추가되었다. 샤드 쿼리 캐시 기능은 샤드 요청 캐시로 이름이 바뀌어 있었다. 샤드 쿼리 캐시의 장점은 한 인덱스 또는 하나 이상의 인덱스에 대해 검색 요청이 실행될 때, 관련된 각 샤드가 로컬에서 검색을 실행하고 해당 로컬 결과를 코디네이팅 노드(coordinating node)에 리턴한다. 해당 코디네이팅 노드는 각 샤드의 로컬 결과를 전체 결과 집합으로 합친다. 샤드 요청 캐시 모듈은 각 샤드의 로컬 결과를 캐시해서 검색 요청에 대한 결과를 즉시 리턴할 수 있도록 한다.


일래스틱서치 5.0버전 이전까지는 두 개의 명백한 문제로 인해 해당 기능이 기본적으로 비활성화였다. JSON의 순서는 결정적(deterministic)이지 않아서 두 요청이 논리적으로 동일할 수도 있지만 JSON 문자열에 렌더링 될 때는 동일하지 않을 수 있다. 전체 JSON 문자열을 기반으로 하는 샤드 캐시 키는 동일한 쿼리가 캐시의 이점을 얻을 수 없다.


대부분의 경우 사용자 쿼리는 시간 기반이고 특히 현재 시간과 관련되어 있으므로 후속 요청은 약간 다른 시간 범위를 갖는 경향이 있다. 따라서 해당 캐시를 활성화하면 캐시 히트가 거의 발생하지 않기 때문에 대부분의 경우 메모리가 낭비될 수 있다.


그러나 일래스틱서치 개발자는 지난 몇 년 동안 해당 이슈를 피하고자 샤드 레벨의 캐시 집계를 즉각적으로 만들어 기본 기능으로 제공하기 위해 많은 노력을 기울였다. 이는 검색 실행 코드의 주요 쿼리 리팩토링을 통해 가능해졌다.


5.0 이전 버전에서는 각 노드에서는 JSON 포맷의 원래 검색 요청을 수신하고 쿼리를 파싱하며 쿼리 구문의 일부로 실행되었던 루씬 쿼리를 실제로 생성하기 위해 샤드의 사용 가능한 정보(매핑과 같은 정보)를 사용했다.


5.0에서는 기존 오버 헤드가 완전히 제거되었다. 쿼리 파싱은 이제 요청을 수신하는 코디네이팅 노드에서만 발생하고 검색 요청을 사용할 수 있는 매핑과 상관 없이 직렬화 할 수 있는 중간 포맷(모든 노드가 이해할 수 있는 중간 쿼리 객체)으로 변경한다. 그런 다음 중재자 쿼리 객체는 모든 노드에서 구문 분석되어 샤드에 있는 매핑과 정보를 기반으로 실제 루씬 쿼리로 변환된다. 7장, '로우 레벨 인덱스 제어'에서 캐시에 대해 자세히 다룰 예정이다. 


샤드 요청 캐시는 일래스틱서치 5.0에서 기본적으로 "size": 0 인 모든 요청에 ​​대해 활성화된다. 샤드 요청 캐시는 사용자가 응답 시 다큐먼트를 리턴하지 않고 집계 결과를 사용해 데이터 전체적인 개요를 얻는 것에 관심있는 분석 사용 사례에 가장 유용하다.

Posted by '김용환'
,

#일래스틱서치 탄생

처음에는 MVEL 지원

https://github.com/mvel/mvel

(얼마 못가 지원하지 않음)



#일래스틱서치 1.4

MVEL에서 그루비로 대체



# 일래스틱서치 1.5

MVEL은 1.5 버전부터 마침내 제거되었다.



# 일래스틱서치 5.0 

일래스틱서치 5.0버전부터 그루비 스크립팅 언어가 Deprecated되었고 5.0 향후 버전에서 제거될 것이다. 그루비는 새로운 언어인 Painless로 대체되었다. 그루비를 계속 사용할 수 있지만 elasticsearch.yml 파일에서 동적 스크립팅을 활성화해야 한다. Painless을 사용하기 위한 추가 설정이 필요하지 않다.


일래스틱서치는 그루비, 파이썬 뿐 아니라 자바스크립트의 언어 플러그인을 지원했었다. 일래스틱서치 5.0.0 버전부터 기존 언어의 플러그인은 사용 중단되었고 Painless으로 대체되었다.



일래스틱서치는 Painless 외에도 다음 스크립트 언어를 지원한다.
* 빠른 사용자 정의 랭킹과 정렬에 주로 사용되는 루씬 표현식
* 검색 템플릿에 사용되는 mustache
* 자바(사용자 정의 플러그인을 작성)


- Painless 예제

* Groovy와 비슷하게 생겼다.




def sum = 0 

def listOfValues = [0, 1, 2, 3]



def sum = 0; 

for (def i = 0; i < 10; i++) { 

    sum += i; 



def sum = 0; 

for ( i in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] )  { 

    sum += i; 



def i = 2; 

def sum = 0; 

while (i > 0) { 

    sum = sum + i; 

    i--; 

  

def year = doc[\"year\"].value; 

if (year < 1800) {

  return 1.0

} else if (year < 1900) {

 return 2.0

} else {

 return year - 1000 

}




Posted by '김용환'
,