'Elastic/Elasticsearch'에 해당되는 글 295건

  1. 2018.04.24 [Elasticsearch] Synonym filter position 문제 개선
  2. 2018.04.19 [Elasticsearch] Synonym filter 테스트
  3. 2018.04.18 [Elasticsearch] elasticsearch-docker plugin 설치는 어떻게?
  4. 2018.04.17 [Elasticsearch] elasticsearch-docker 만들어 보기
  5. 2018.04.12 [Elasticsearch] WildcardQuery 알아보기
  6. 2018.04.06 [Elasticsearch] Elasticsearch Case Study 1) Data 노드에 Index/Shard 구성 시작 해보기
  7. 2018.04.05 [Elasticsearch] 쉽게 Elasticsearch Estimation 하기
  8. 2018.04.04 [Elasticsearch] Contribution 하기 위한 준비 작업
  9. 2018.04.03 [Elasticsearch] JSON 스트링으로 질의요청
  10. 2018.01.30 [Elasticsearch] elasticsearch-analysis-arirang 버그 수정

[Elasticsearch] Synonym filter position 문제 개선

Elastic/Elasticsearch 2018.04.24 15:52

이미 synonym filter 테스트 관련 글을 공유 했었습니다.

- [Elasticsearch] Synonym filter 테스트


이 테스트에서 발생한 문제는 동의어에 대한 position 정보가 잘 못되는 것입니다.

테스트 환경은 기본 Elasticsearch 6.x 에서 진행 되었습니다. 


아래는 SynonymFilter 코드 내 주석 입니다.


[SynonymFilter.java]

 Matches single or multi word synonyms in a token stream.

 This token stream cannot properly handle position

 increments != 1, ie, you should place this filter before

 filtering out stop words.


그리고 아래는 동의어 처리 시 문제가 발생 하는 부분의 코드 입니다.


[SynonymMap.java]

 /** Sugar: analyzes the text with the analyzer and

 *  separates by {@link SynonymMap#WORD_SEPARATOR}.

 *  reuse and its chars must not be null. */

public CharsRef analyze(String text, CharsRefBuilder reuse) throws IOException {

  try (TokenStream ts = analyzer.tokenStream("", text)) {

    CharTermAttribute termAtt = ts.addAttribute(CharTermAttribute.class);

    PositionIncrementAttribute posIncAtt = ts.addAttribute(PositionIncrementAttribute.class);

    ts.reset();

    reuse.clear();

    while (ts.incrementToken()) {

      int length = termAtt.length();

      if (length == 0) {

        throw new IllegalArgumentException("term: " + text + " analyzed to a zero-length token");

      }

      if (posIncAtt.getPositionIncrement() != 1) {

        throw new IllegalArgumentException("term: " + text + " analyzed to a token (" + termAtt +

                                           ") with position increment != 1 (got: " + posIncAtt.getPositionIncrement() + ")");

      }

      reuse.grow(reuse.length() + length + 1); /* current + word + separator */

      int end = reuse.length();

      if (reuse.length() > 0) {

        reuse.setCharAt(end++, SynonymMap.WORD_SEPARATOR);

        reuse.setLength(reuse.length() + 1);

      }

      System.arraycopy(termAtt.buffer(), 0, reuse.chars(), end, length);

      reuse.setLength(reuse.length() + length);

    }

    ts.end();

  }

  if (reuse.length() == 0) {

    throw new IllegalArgumentException("term: " + text + " was completely eliminated by analyzer");

  }

  return reuse.get();

}


기본적으로 동의어 처리에 대한 문제는 이미 lucene 레벨에서 개선이 되었습니다.

관련 참고 링크는 아래와 같습니다.


[Reference links]

https://issues.apache.org/jira/browse/LUCENE-6664

http://blog.mikemccandless.com/2012/04/lucenes-tokenstreams-are-actually.html


이와 같이 개선된 synonym filter 를 elasticsearch 에서는 아래와 같이 사용 할 수 있습니다.


[Reference links]

https://www.elastic.co/guide/en/elasticsearch/reference/master/analysis-synonym-graph-tokenfilter.html



[Create index]

PUT /syngtest

{

  "settings": {

    "index.number_of_shards": 1,

    "index.number_of_replicas": 0,

    "index": {

      "analysis": {

        "analyzer": {

          "arirang_custom": {

            "tokenizer": "arirang_tokenizer",

            "filter": [

              "lowercase",

              "trim",

              "arirang_filter",

              "custom_synonym"

            ]

          }

        },

        "filter": {

          "custom_synonym": {

            "type": "synonym_graph",

            "synonyms": [

              "henry,헨리,앙리",

              "신해철,마왕"

            ]

          }

        }

      }

    }

  }

}


[Request analyze]

GET /syngtest/_analyze

{

  "tokenizer": "arirang_tokenizer",

  "filter": [

    "lowercase",

    "trim",

    "arirang_filter",

    "custom_synonym"

  ],

  "text": "신해철은 henry"

}


[Analyzed result]

{

  "tokens": [

    {

      "token": "마왕",

      "start_offset": 0,

      "end_offset": 3,

      "type": "SYNONYM",

      "position": 0

    },

    {

      "token": "신해철",

      "start_offset": 0,

      "end_offset": 3,

      "type": "korean",

      "position": 0

    },

    {

      "token": "헨리",

      "start_offset": 5,

      "end_offset": 10,

      "type": "SYNONYM",

      "position": 1

    },

    {

      "token": "앙리",

      "start_offset": 5,

      "end_offset": 10,

      "type": "SYNONYM",

      "position": 1

    },

    {

      "token": "henry",

      "start_offset": 5,

      "end_offset": 10,

      "type": "word",

      "position": 1

    }

  ]

}


특별히 코드를 수정 하거나 하지 않고 문제가 해결 된 것을 확인 하실 수 있습니다.

왜 해결 되었는지는 위 synonym graph filter 에 대해서 문서를 보시면 되겠습니다.


Trackback 0 : Comment 0

[Elasticsearch] Synonym filter 테스트

Elastic/Elasticsearch 2018.04.19 16:19

커뮤니티에 질문 주신 내용이 있어서 바쁘지만 테스트 결과 공유 드립니다.

커뮤니티에 질문 올려 주신 분이 계셔서 직접 테스트 진행 했습니다.

제가 position 관련 에러 수정을 위한 테스트 시간이 없어서 인명 사전 등록 방법으로 처리 했는데요.

수정이 필요 하시면 KoreanFilter 코드를 수정 하시면 됩니다.


설치 및 테스트 Elasticsearch Version)

6.0.0


Arirang plugin 설치)

$ bin/elasticsearch-plugin install https://github.com/HowookJeong/elasticsearch-analysis-arirang/releases/download/6.0.0/elasticsearch-analysis-arirang-6.0.0.zip


Index 삭제)

DELETE syntest


{

  "error": {

    "root_cause": [

      {

        "type": "index_not_found_exception",

        "reason": "no such index",

        "resource.type": "index_or_alias",

        "resource.id": "syntest",

        "index_uuid": "_na_",

        "index": "syntest"

      }

    ],

    "type": "index_not_found_exception",

    "reason": "no such index",

    "resource.type": "index_or_alias",

    "resource.id": "syntest",

    "index_uuid": "_na_",

    "index": "syntest"

  },

  "status": 404

}


Index 생성)

PUT /syntest

{

  "settings": {

    "index.number_of_shards": 1,

    "index.number_of_replicas": 0,

    "index": {

      "analysis": {

        "analyzer": {

          "arirang_custom": {

            "tokenizer": "arirang_tokenizer",

            "filter": [

              "lowercase",

              "trim",

              "custom_synonym",

              "arirang_filter"

            ]

          }

        },

        "filter": {

          "custom_synonym": {

            "type": "synonym",

            "synonyms": [

              "henry,헨리,앙리",

              "신해철,마왕"

            ]

          }

        }

      }

    }

  }

}


{

  "acknowledged": true,

  "shards_acknowledged": true,

  "index": "syntest"

}


Analyze 실행)

GET /syntest/_analyze

{

  "tokenizer": "arirang_tokenizer",

  "filter": [

    "lowercase",

    "trim",

    "custom_synonym",

    "arirang_filter"

  ],

  "text": "신해철"

}


{

  "tokens": [

    {

      "token": "신해철",

      "start_offset": 0,

      "end_offset": 3,

      "type": "korean",

      "position": 0

    },

    {

      "token": "신해",

      "start_offset": 0,

      "end_offset": 2,

      "type": "korean",

      "position": 0

    },

    {

      "token": "해철",

      "start_offset": 1,

      "end_offset": 3,

      "type": "korean",

      "position": 1

    },

    {

      "token": "마왕",

      "start_offset": 0,

      "end_offset": 3,

      "type": "SYNONYM",

      "position": 1

    }

  ]

}


동의어 처리가 되지 않은 이유)

GET /syntest/_analyze

{

  "tokenizer": "arirang_tokenizer",

  "text": "신해철은 henry"

}


{

  "tokens": [

    {

      "token": "신해철은",

      "start_offset": 0,

      "end_offset": 4,

      "type": "korean",

      "position": 0

    },

    {

      "token": "henry",

      "start_offset": 5,

      "end_offset": 10,

      "type": "word",

      "position": 1

    }

  ]

}


tokenizer 에서 추출한 토큰은 위와 같이 두개 입니다.

아래는 filter 를 적용한 내용입니다.


GET /syntest/_analyze

{

  "tokenizer": "arirang_tokenizer",

  "filter": [

    "lowercase",

    "trim",

    "custom_synonym",

    "arirang_filter"

  ],

  "text": "신해철은 henry"

}


{

  "tokens": [

    {

      "token": "신해철",

      "start_offset": 0,

      "end_offset": 3,

      "type": "korean",

      "position": 0

    },

    {

      "token": "신해철은",

      "start_offset": 0,

      "end_offset": 4,

      "type": "korean",

      "position": 0

    },

    {

      "token": "신해",

      "start_offset": 0,

      "end_offset": 2,

      "type": "korean",

      "position": 0

    },

    {

      "token": "해철",

      "start_offset": 1,

      "end_offset": 3,

      "type": "korean",

      "position": 1

    },

    {

      "token": "철은",

      "start_offset": 2,

      "end_offset": 4,

      "type": "korean",

      "position": 2

    },

    {

      "token": "henry",

      "start_offset": 5,

      "end_offset": 10,

      "type": "word",

      "position": 3

    },

    {

      "token": "헨리",

      "start_offset": 5,

      "end_offset": 10,

      "type": "SYNONYM",

      "position": 3

    },

    {

      "token": "앙리",

      "start_offset": 5,

      "end_offset": 10,

      "type": "SYNONYM",

      "position": 3

    }

  ]

}


위에 추출된 term 목록을 보면 "마왕" 이라는 동의어가 추가 되지 않은것을 볼 수 있습니다.

이것은 두 가지 방법으로 해결이 가능 합니다.

사전에 "신해철" 이라는 인명 사전 정보를 등록 하시면 됩니다.

기본적으로 tokenzier 과정 후 filter 처리가 되면서 사전에 등록된 정보로 term 구성이 되기 때문에 사전에 누락 된 경우는 일반적으로 KoreanFilter 에 의해서 bigram 처리가 됩니다.

다른 한 가지는 position 정보가 구성 시 오류가 나지 않도록 코드를 수정 하는 것입니다.

KoreanFilter 코드를 참고 하셔서 테스트 및 수정 하시면 됩니다.


아래는 사전에 "신해철" 추가 후 실행한 방법 입니다.


GET /syntest/_analyze

{

  "tokenizer": "arirang_tokenizer",

  "filter": [

    "lowercase",

    "trim",

    "arirang_filter",

    "custom_synonym"

  ],

  "text": "신해철은 henry"

}


{

  "tokens": [

    {

      "token": "신해철",

      "start_offset": 0,

      "end_offset": 3,

      "type": "korean",

      "position": 0

    },

    {

      "token": "마왕",

      "start_offset": 0,

      "end_offset": 3,

      "type": "SYNONYM",

      "position": 0

    },

    {

      "token": "henry",

      "start_offset": 5,

      "end_offset": 10,

      "type": "word",

      "position": 1

    },

    {

      "token": "헨리",

      "start_offset": 5,

      "end_offset": 10,

      "type": "SYNONYM",

      "position": 1

    },

    {

      "token": "앙리",

      "start_offset": 5,

      "end_offset": 10,

      "type": "SYNONYM",

      "position": 1

    }

  ]

}


Trackback 0 : Comment 0

[Elasticsearch] elasticsearch-docker plugin 설치는 어떻게?

Elastic/Elasticsearch 2018.04.18 15:44

Elasticsearch docker 만들어 보기 참고하세요.


초간단 예제를 보여 드리겠습니다.

Dockerfile 에 추가해 주시면 됩니다.


# plugin 을 설치 합니다.

RUN bin/elasticsearch-plugin install --batch analysis-icu


$ docker run elasticsearch-6.2.3-ubuntu-14.04-jdk8u152 ls -al plugins/

total 12

drwxr-xr-x 1 elasticsearch elasticsearch 4096 Apr 18 06:38 .

drwxr-xr-x 1 elasticsearch elasticsearch 4096 Apr 18 06:37 ..

drwxr-xr-x 2 elasticsearch elasticsearch 4096 Apr 18 06:38 analysis-icu


참 쉽습니다.

Trackback 0 : Comment 0

[Elasticsearch] elasticsearch-docker 만들어 보기

Elastic/Elasticsearch 2018.04.17 18:14

이미 Elastic 사에서 docker 를 제공하고 있습니다.

정보는 아래 링크를 참고하세요.


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

https://github.com/elastic/elasticsearch-docker

https://docs.docker.com/get-started/


Docker 를 이용해서 이미지를 만들어 보고 실행 및 클러스터 구성을 어떻게 하는지 단계 별 실행 코드를 따라 하면서 배워 보도록 하겠습니다.

그냥 따라만 하시면 될 겁니다. (Maybe)


제 개발 환경은 mac 입니다.

- docker 당연히 설치가 되어 있어야 합니다.

그 이외는 음... 그냥 개발자시면 쉽게 하실 수 있을 실거예요. ^^


Step 1) 이미지를 만들기 위한 repo 를 하나 만듭니다.

$ mkdir elasticsearch-docker

$ cd elasticsearch-docker


Step 2) 이미지에 패키징 할 패키지들을 준비해 둡니다.

$ wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.2.3.tar.gz

$ download jdk-8u152-linux-x64.tar.gz


Step 3) 혹시 커스텀 설정을 하실 거라면 만들어 보세요.

$ mkdir config

$ touch elasticsearch.yml

$ touch jvm.options

$ touch log4j2.properties


# elasticsearch default config 파일로 구성을 합니다.

# 또는 변경이 필요할 경우 작성을 합니다.


Step 4) 이미지 생성을 위한 도커 파일을 만듭니다.

$ vi Dockerfile

From ubuntu:14.04

MAINTAINER HENRY JEONG sophistlv@gmail.com


ARG arg_user_home

ARG arg_es_version


ENV PATH $arg_user_home/apps/elasticsearch/bin:$arg_user_home/apps/jdk/bin:$PATH

ENV ES_HOME $arg_user_home/apps/elasticsearch

ENV JAVA_HOME $arg_user_home/apps/jdk


RUN groupadd -g 1000 elasticsearch && useradd elasticsearch -u 1000 -g 1000 -m -b $arg_user_home -d $arg_user_home -s /bin/bash

USER 1000


# 기본 디렉토리를 생성 합니다.

WORKDIR $arg_user_home

RUN mkdir apps


# 현재 작업 디렉토리를 선언 합니다.

WORKDIR $arg_user_home/apps


# 아래와 같이 다운로드를 받거나 이미 받아 놓은 파일을 추가 합니다.

#RUN wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-$arg_es_version.tar.gz

COPY elasticsearch-$arg_es_version.tar.gz .

COPY jdk-8u152-linux-x64.tar.gz .


# 압축을 해제 합니다.(자동으로 해제 됩니다.)

RUN tar -xvzf elasticsearch-$arg_es_version.tar.gz

RUN tar -xvzf jdk-8u152-linux-x64.tar.gz

RUN rm -f elasticsearch-$arg_es_version.tar.gz

RUN rm -f jdk-8u152-linux-x64.tar.gz


# 설정 파일을 추가 합니다.

COPY config/elasticsearch.yml elasticsearch-$arg_es_version/config/

COPY config/jvm.options elasticsearch-$arg_es_version/config/

COPY config/log4j2.properties elasticsearch-$arg_es_version/config/


# symlink 를 설정 합니다.

RUN ln -s elasticsearch-$arg_es_version elasticsearch

RUN ln -s jdk1.8.0_152 jdk


# WORKDIR 을 변경 합니다.

WORKDIR elasticsearch-$arg_es_version

RUN set -ex && for path in data logs config/scripts; do \

        mkdir -p "$path"; \

        chown -R elasticsearch:elasticsearch "$path"; \

    done


# 데몬을 실행 합니다.

#CMD bin/elasticsearch


EXPOSE 9200 9201 9300 9301


Step 5) 이미지를 생성 합니다.

$ docker build -t elasticsearch-6.2.3-ubuntu-14.04-jdk8u152 . --build-arg arg_user_home=/home/es --build-arg arg_es_version=6.2.3

Sending build context to Docker daemon  218.9MB

Step 1/26 : From ubuntu:14.04

---> 67759a80360c

Step 2/26 : MAINTAINER HENRY JEONG sophistlv@gmail.com

---> Using cache

---> be0de8404ce2

Step 3/26 : ARG arg_user_home

---> Using cache

---> 9cad1b4a18c5

Step 4/26 : ARG arg_es_version

---> Using cache

---> 693e1b4ae411

Step 5/26 : ENV PATH $arg_user_home/apps/elasticsearch/bin:$arg_user_home/apps/jdk/bin:$PATH

---> Using cache

---> 5a249008ab07

Step 6/26 : ENV ES_HOME $arg_user_home/apps/elasticsearch

---> Using cache

---> 095bc65a6dfb

Step 7/26 : ENV JAVA_HOME $arg_user_home/apps/jdk

---> Using cache

---> cb02bd60ea16

Step 8/26 : RUN groupadd -g 1000 elasticsearch && useradd elasticsearch -u 1000 -g 1000 -m -b $arg_user_home -d $arg_user_home -s /bin/bash

---> Running in 64ebd0c6b8cf

Removing intermediate container 64ebd0c6b8cf

---> 49759958cddd

Step 9/26 : USER 1000

---> Running in 849c7bde5f44

Removing intermediate container 849c7bde5f44

---> e0f04944d08c

Step 10/26 : WORKDIR $arg_user_home

Removing intermediate container a7e04ccfe107

---> c5b262000886

Step 11/26 : RUN mkdir apps

---> Running in 0272f8c59b01

Removing intermediate container 0272f8c59b01

---> 5e860b3ae335

Step 12/26 : WORKDIR $arg_user_home/apps

Removing intermediate container 093bbfc52201

---> 541e34eb3f99

Step 13/26 : COPY elasticsearch-$arg_es_version.tar.gz .

---> b7f35e466950

Step 14/26 : COPY jdk-8u152-linux-x64.tar.gz .

---> d47f3d93cfd6

Step 15/26 : RUN tar -xvzf elasticsearch-$arg_es_version.tar.gz

---> Running in ec1b02ec10b4

...중략...

Removing intermediate container ec1b02ec10b4

---> 79d8bec8ee89

Step 16/26 : RUN tar -xvzf jdk-8u152-linux-x64.tar.gz

---> Running in c8ae086e2868

Removing intermediate container b94059a73a2c

---> 6fa8928d2367

...중략...

Step 17/26 : RUN rm -f elasticsearch-$arg_es_version.tar.gz

---> Running in beec4cdec4eb

Removing intermediate container beec4cdec4eb

---> 0c30468566ea

Step 18/26 : RUN rm -f jdk-8u152-linux-x64.tar.gz

---> Running in 998cd2eb3d33

Removing intermediate container 998cd2eb3d33

---> 8e1d588a3bbc

Step 19/26 : COPY config/elasticsearch.yml elasticsearch-$arg_es_version/config/

---> b2faa21e1692

Step 20/26 : COPY config/jvm.options elasticsearch-$arg_es_version/config/

---> 36c3ce020763

Step 21/26 : COPY config/log4j2.properties elasticsearch-$arg_es_version/config/

---> 48314fe634e1

Step 22/26 : RUN ln -s elasticsearch-$arg_es_version elasticsearch

---> Running in 2f7610ab8ce4

Removing intermediate container 2f7610ab8ce4

---> 539eb5fce438

Step 23/26 : RUN ln -s jdk1.8.0_152 jdk

---> Running in 1f4585206800

Removing intermediate container 1f4585206800

---> f61c467a833b

Step 24/26 : WORKDIR elasticsearch-$arg_es_version

Removing intermediate container 786de237b577

---> a92587ddf7bf

Step 25/26 : RUN set -ex && for path in data logs config/scripts; do         mkdir -p "$path";         chown -R elasticsearch:elasticsearch "$path";     done

---> Running in dfe771b1d02d

+ mkdir -p data

+ chown -R elasticsearch:elasticsearch data

+ mkdir -p logs

+ chown -R elasticsearch:elasticsearch logs

+ mkdir -p config/scripts

+ chown -R elasticsearch:elasticsearch config/scripts

Removing intermediate container dfe771b1d02d

---> 90193d0f5dcc

Step 26/26 : EXPOSE 9200 9201 9300 9301

---> Running in b14404086bc4

Removing intermediate container b14404086bc4

---> a2c69d28a015

Successfully built a2c69d28a015

Successfully tagged elasticsearch-6.2.3-ubuntu-14.04-jdk8u152:latest


Step 6) Elasticsearch 가 사용할 네트워크를 생성 합니다.

$ docker network create es-net

$ docker network ls

NETWORK ID          NAME                DRIVER              SCOPE

ed35ea6eb949        bridge              bridge              local

a6c8b4fd7996        es-net              bridge              local

f3ab4273e30a        host                host                local

9d6aa0be922f        none                null                local


Step 7) 만들어진 이미지가 잘 되었는지 한번 명령어를 실행 시켜 봅니다.

$ docker run elasticsearch-6.2.3-ubuntu-14.04-jdk8u152 ls -al

total 248

drwxr-xr-x  1 elasticsearch elasticsearch   4096 Apr 17 07:45 .

drwxr-xr-x  1 elasticsearch elasticsearch   4096 Apr 17 07:45 ..

-rw-r--r--  1 elasticsearch elasticsearch  11358 Mar 13 10:02 LICENSE.txt

-rw-r--r--  1 elasticsearch elasticsearch 191887 Mar 13 10:07 NOTICE.txt

-rw-r--r--  1 elasticsearch elasticsearch   9268 Mar 13 10:02 README.textile

drwxr-xr-x  2 elasticsearch elasticsearch   4096 Apr 17 07:44 bin

drwxr-xr-x  1 elasticsearch elasticsearch   4096 Apr 17 07:45 config

drwxr-xr-x  2 elasticsearch elasticsearch   4096 Apr 17 07:45 data

drwxr-xr-x  2 elasticsearch elasticsearch   4096 Mar 13 10:08 lib

drwxr-xr-x  1 elasticsearch elasticsearch   4096 Mar 13 10:08 logs

drwxr-xr-x 16 elasticsearch elasticsearch   4096 Mar 13 10:08 modules

drwxr-xr-x  2 elasticsearch elasticsearch   4096 Mar 13 10:08 plugins


Step 8) 마지막으로 클러스터 구성을 테스트 합니다.

# -d 를 추가 하면 daemonize 로 동작


$ docker run -p 9200:9200 -p 9300:9300 elasticsearch-6.2.3-ubuntu-14.04-jdk8u152 bin/elasticsearch

# Single node 실행


$ docker run --memory=2g -e ES_JAVA_OPTS="-Xms512m -Xmx512m" -p 9200:9200 -p 9300:9300 -u 1000 elasticsearch-6.2.3-ubuntu-14.04-jdk8u152:latest \

bin/elasticsearch \

-Ecluster.name=cluster-docker \

-Enode.name=node-docker1 \

-Enode.master=true \

-Enode.data=true \

-Ediscovery.zen.minimum_master_nodes=1 \

-Enetwork.host=0.0.0.0 \

-Ediscovery.zen.ping.unicast.hosts=192.168.221.237:9301 \

-Ehttp.port=9200 \

-Etransport.tcp.port=9300


$ docker run --memory=2g -e ES_JAVA_OPTS="-Xms512m -Xmx512m" -p 9201:9200 -p 9301:9300 -u 1000 elasticsearch-6.2.3-ubuntu-14.04-jdk8u152:latest \

bin/elasticsearch \

-Ecluster.name=cluster-docker \

-Enode.name=node-docker2 \

-Enode.master=false \

-Enode.data=true \

-Ediscovery.zen.minimum_master_nodes=1 \

-Enetwork.host=0.0.0.0 \

-Ediscovery.zen.ping.unicast.hosts=192.168.221.237:9300 \

-Ehttp.port=9200 \

-Etransport.tcp.port=9300


별로 어려운것 없이 쉽게 할 수 있습니다.

여기서 개선 및 업그레이드는 각자 편하게 하시면 될 것 같습니다.

Trackback 0 : Comment 0

[Elasticsearch] WildcardQuery 알아보기

Elastic/Elasticsearch 2018.04.12 15:46

참고문서)

https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-wildcard-query.html


WildcardQuery 는 사실 추천 하지 않지만 필요에 따라 사용해야 할 수도 있습니다.

성능적으로 좋은 API 는 아니기 때문에 추천 하지 않는 것이지 기능적으로는 유용할 수도 있습니다.


[Field Type]

Keyword : not_analyzed

Text(String) : analyzed


[Lucene]

WildcardQuery -> MultiTermQuery


[Elasticsearch]

WildcardQueryBuilder


[Usage]

WildcardQuery 는 기본적으로 field type 의 색인 속성과는 상관 없습니다.

not_analyzed field 에 대해서 질의 할 때와 analyzed field 에 대해서 질의 할 때 조금 모호 할 수 있습니다.

즉, term query 를 사용하기 때문에 아래와 같이 예를 들겠습니다.

Field name : title

Text value : nike clothes


Case 1)

not_analyzed field)

term : nike clothes


"query" : {

"wildcard" : {

"title" : "ni*e"

}

}


not matched


결과가 나오지 않는 이유는 추출된 term 이 "nike clothes" 이기 때문에 "ni*e" 로 했을 경우 추출 텀의 제일 마지막 문자가 e 가 아니기 때문에 매칭이 되지 않은 것입니다.

매칭이 되게 하려면 "ni*" 또는 "ni*s" 로 해야 매칭이 됩니다.


Case 2)

analyzed field)

terms : [nike, clothes]


"query" : {

"wildcard" : {

"title" : "ni*e"

}

}


matched


이 경우는 추출된 term 이 두 개 이며, nike 라는 텀에 대해서 매칭이 된 것입니다.



Trackback 0 : Comment 0

[Elasticsearch] Elasticsearch Case Study 1) Data 노드에 Index/Shard 구성 시작 해보기

Elastic/Elasticsearch 2018.04.06 10:13

Elasticsearch Case Study 1) Data 노드에 Index/Shard 구성 시작 해보기

- Data Node 3개, Active Index 1개

- Data Node Spec)

CPU : 16 cores

- 지속적인 Read/Write operaiton 이 발생 하는 경우로 가정 하겠습니다.


Primary/Replica Shard Sizing)

- Shard 구성을 하실 때 가장 쉽게 접근 할 수 있는 방법은 CPU 코어 크기를 가지고 판단 하시면 됩니다.

- Data 노드 하나당 active shard 로 배치 할 수 있는 가장 기본은 코어 크기와 똑같이 구성 하시는 것입니다.


위에 16 코어로 가정했기 때문에 Data 노드에는 16개의 Shard 를 할당 할 수 있습니다.


Elasticsearch Settings 정보)

curl -XPUT http://localhost:9200/case-study-1/_settings '{

    "settings" : {

        "index" : {

            "number_of_shards" : 15,

            "number_of_replicas" : 2

        }

    }

}'


이와 같이 Index 를 생성 하게 되면 아래와 같이 shard 가 배치 됩니다.


Data node 1 : 

Primary Shards : 0, 1, 2, 3, 4

Replica Shards : 5, 6, 7, 8, 9, 10, 11, 12, 13, 14

Data node 2 :

Primary Shards : 5, 6, 7, 8, 9

Replica Shards : 0, 1, 2, 3, 4, 10, 11, 12, 13, 14

Data node 3 :

Primary Shards : 10, 11, 12, 13, 14

Replica Shards : 5, 6, 7, 8, 9, 0, 1, 2, 3, 4


보시게 되면 모든 Data 노드에 Shard 가 15개씩 할당 되어 있는 것을 확인 하실 수 있습니다.

여기까지 확인 하셨으면 이제 부터가 시작 입니다.


Data 노드에 Index, Shard에 대한 기본 설정은 했지만 이게 최적화 된 것인지는 알수 없습니다.

그래서 사용환경에 맞춰서 성능 테스트를 해 보셔야 합니다.


아래 질문에 답변을 해보세요.


1. 내가 사용하고자 하는 클러스터는 질의 및 분석에 최적화 되어야 한다.

2. 내가 사용하고자 하는 클러스터는 색인에 최적화 되어야 한다.

3. 내가 사용하고자 하는 클러스터는 질의, 분석 그리고 색인 모두 최적화 되어야 한다.


1번을 원하신다면 아래 항목들에 대해서 검토를 해보시면 좋습니다.

질의 와 분석은 CPU 와 Memory 를 많이 사용하기 때문에 충분한 자원이 준비 되어 있어야 합니다.

그리고 Document 에 대한 mapping 정보 최적화가 필요 합니다.

1. Match query 종류를 사용해야 하는가? (주로 Full text query를 의미 합니다.)

- Elastic 사에서는 Full text queries 라고 합니다.

2. Term query 종류를 사용해야 하는가? (주로 Exact match query를 의미 합니다.)

- Elastic 사에서는 Term level queries 라고 합니다.

3. Aggregation 질의가 많은가?

4. Nested 유형의 Aggregation 질의가 많은가?


2번을 원하신다면 아래 항목들에 대해서 검토를 해보시면 좋습니다.

색인 작업은 CPU 와 Disk I/O 성능에 영향을 많이 받습니다.

또한 사용하는 형태소 분석기에 따른 성능 변화도 확인을 하셔야 합니다.


사실 색인에 최적화 라는건 Bulk Indexing 이 아니고서는 다른 주제 인것 같습니다.

로그 데이터의 경우 보통은 Data 노드의 처리량을 고려해서 앞단에 Queue 를 사용하고,

여기서 Beats 나 Logstash 와 같은 Shipper 를 이용해서 Elasticsearch 로 색인하도록 구성을 합니다.

결과적으로 Queue + Beats/Logstash + Elasticsearch 에 대한 최적화 작업 없이는 어려운 작업 입니다.


Elasticsearch 관점에서 바라보면:Bulk Indexing)

1. Dynamic mapping 사용을 피하는게 좋습니다.

2. 불필요한 Analyzed 과정을 제거 하는게 좋습니다.

3. Bulk 요청 시 Replica 와 Refresh 를 사용하지 않는게 좋습니다.

4. _all Field 사용을 피하는게 좋습니다.

5. _id 는 가능 하면 임의 설정을 하지 않는게 좋습니다.

6. Index Buffer Size 를 512MB 정도까지 크게 설정 하는게 좋습니다.

7. 기타 등등 사소한 튜닝 팁들이 많습니다.


3번을 원하신다면 아래 항목들에 대해서 검토를 해보시면 좋습니다.

가장 어려운 요구사항 입니다.

이런 경우 클러스터의 노드와 인덱스 구성을 분리해서 사용하시는게 좋습니다.

1. Cross Cluster Search(Tribe Node) 에 대해서 검토해 봅니다.

2. Hot-Warm Architecture 에 대해서 검토해 봅니다.

3. Index Alias 기능에 대해서 검토해 봅니다.

4. Shrink, Split, Reindex, Rollover, Rollup 기능에 대해서 검토해 봅니다.

5. Snapshot 과 Restore 기능에 대해서 검토해 봅니다.


이번 Case Study 는 아주 단순 합니다.

요구사항은 알수 없고 단순히 Data 노드 규모와 스펙만으로 Index/Shard 배치를 설정 하는 것이였습니다.

"왜 이렇게/저렇게 해야 하지?" 라는 궁금증이 드시는 부분은 이해를 돕기 위해 추가적인 설명이 들어가야 하는데 과감히 생략 했습니다. (커뮤니티에 질문 주시거나 저를 만나시면 물어보세요. 친절히 설명해 드리겠습니다.)


항상 반복 되는 이야기지만,

사용 환경에 맞게 테스트 하시고 최적화 하는게 정답입니다.

시작 하기 전에 조금이나마 도움이 될 수 있는 내용을 작성한 것이지 이대로 하면 된다는 것은 아닙니다.

알아야 할 것도 많고 검증 해야 할 것도 많습니다.

시간과 인력이 부족 하시다면 Elastic 사에서 지원하는 좋은 프로그램들이 있으니 참고 하셔도 좋을 것 같습니다.


궁금 하신 것들이 있으시면 Facebook 유저 커뮤니티에 질문으로 올려 주세요.

제가 할 수 있다면 도움 드릴 수 있도록 하겠습니다.

Trackback 0 : Comment 0

[Elasticsearch] 쉽게 Elasticsearch Estimation 하기

Elastic/Elasticsearch 2018.04.05 15:44

Elasticsearch 를 이용해서 클러스터를 구성 하거나 인덱스를 구성 할 때 아는게 하나도 없는 상황에서 규모에 대한 평가를 하기 위한 기본 정보로 사용하시면 좋을 것 같아 공유 합니다.


기본 전제는 사용하는 환경에 맞게 테스트 및 최적화를 하셔야 합니다.


  • 1 shard around 20GB (max 50GB)


일반적인 서비스용 데이터에 대한 Shard 크기는 최대 20GB 를 넘지 않도록 설계 하시는게 좋으며, 로그 데이터의 경우 50GB 를 넘지 않도록 설계 하시면 됩니다.

이를 기준으로 사용 환경에 맞춰 성능 테스트를 하시고 크기를 최적화 하시면 됩니다.


  • Machine Spec
    • Master ( 1/2 of search ) < Search ( 1/2 of data ) <= Data
    • Minimum Master Node Spec ( m4.large )
      • CPU 2 cores
      • MEM 8GB


장비는 스펙이 좋으면 좋을 수록 좋습니다. 이건 다다익선이죠. 하지만 비용 문제가 있기 때문에 적절한 스펙 선정을 해야 합니다.

장비 하나에 인스턴스 하나를 띄운다고 가정 하고 일반적인 검색엔진 추천 스펙으로 정의 하면) 

장비 스펙이지 노드 스펙이 아닙니다.


  • CPU : 32 cores
  • MEM : 64GB


위 장비 스펙을 Data 노드라고 가정하면,
    • Search(Client) 노드의 장비 스펙은)
      • 32 cores X 32GB
      • 16 cores X 32GB


    • Master 노드의 장비 스펙은)
      • 8 cores X 16GB
      • 4 cores X 16GB


  • Primary Shards
    • CPU core size eq primary shards ( 1/2 of CPU cores )


위에 정리한 내용들의 출발은 알고 있는 정보가 전혀 없다는 가정에서 시작한 것입니다.

처음 시작 하시는 분들에게는 어디서 부터 어떻게 해야 할지 모르기 때문에 시작 할 수 있는 정보가 있다면 조금은 시간낭비나 고민을 덜어 드릴수 있지 않을까 싶어서 공유 합니다.


인덱스와 샤드에 대한 생성과 배치 전략에 대해서도 공유를 드리도록 하겠습니다.

그 전에 아주 옛날에 작성한 글 하나가 있어서 링크 투척하고

[Elasticsearch] replica & shard 이해하기.


약간의 부연 설명만 하고 마무리 하겠습니다.


1. Primary shard

원본 데이터 입니다.

한번 정의 하면 변경 할 수 없으며, 현재는 shrink, split, reindex 등의 API 를 이용해서 뭔가의 조작은 가능 합니다. (이것도 나중에 관련 API 설명을 해야 겠군요..)



2. Replica shard

복제 데이터 입니다.

동적으로 변경이 가능 하며, 장애 방지 및 검색 질의에 대한 throughput 향상에 활용 합니다.

(참고로 Replica shard 는 Primary shard 로 승격이 가능 합니다. - 참고문서)

Trackback 0 : Comment 0

[Elasticsearch] Contribution 하기 위한 준비 작업

Elastic/Elasticsearch 2018.04.04 12:31

Elasticsearch 소스코드를 수정 하거나 디버깅을 하고 싶을 때가 있습니다.

로컬에서 빌드 부터 해야 가능하겠죠.


특별히 contributing 을 목적으로 하지는 않지만, 그래도 이왕이면 버그 수정도 하고 contribution 도 하면 좋겠죠.


아래는 이미 문서에 자세히 나와 있는 내용을 그냥 요약 정도 해본 내용입니다.

(기억을 위해 한번 더 작성해 본 내용입니다.)


Reference)

https://github.com/elastic/elasticsearch/blob/master/CONTRIBUTING.md

https://github.com/elastic/elasticsearch/blob/master/TESTING.asciidoc


사전 준비 도구)

- JDK 10 다운로드 및 설치 (Build 용)

- JDK 8 다운로드 및 설치 (Runtime 용)

- Gradle 4.3 다운로드 및 설치


JDK 10 설치 후 환경변수 설정)

$ vi .bash_profile

export JAVA_HOME=$(/usr/libexec/java_home)

export RUNTIME_JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home


Intellij 환경설정)

This can be achieved by adding the -Didea.no.launcher=true JVM option. 

IntelliJ, go to Run->Edit Configurations...->Defaults->JUnit->VM options and input -ea.

$ ./gradlew idea


Formatting 설정)

- Java indent is 4 spaces

- Line width is 140 characters

- IntelliJ: Preferences/Settings->Editor->Code Style->Java->Imports

- Class count to use import with '*' and Names count to use static import with '*'. Set their values to 99999


Elasticsearch run)

$ ./gradlew run


# 실행 시 9200과 9300 port 로 실행 중인 elasticsearch daemon 이 있으면 에러 발생 합니다.


Logging level 설정)

# path : distribution/src/config/log4j2.properties


$ vi log4j2.properties

ASIS)

rootLogger.level = info


TOBE)

rootLogger.level = debug


Create distribution)

$ ./gradlew assemble

$ ./gradlew check


Trackback 0 : Comment 0

[Elasticsearch] JSON 스트링으로 질의요청

Elastic/Elasticsearch 2018.04.03 13:41

예전에도 JSON 스트링을 가지고 setSource() 함수로 질의 했었는데요.

필요하신 분들이 계신것 같아 쉬운 샘플 코드 올려 봅니다.


[Source Code]

package org.elasticsearch.action.search;

import org.elasticsearch.client.Client;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.transport.client.PreBuiltTransportClient;

public class HelloSearchSourceBuilder {

public static void main (String[] args) {
Client client;
client = new PreBuiltTransportClient(Settings.EMPTY);

SearchRequestBuilder searchRequestBuilder = client.prepareSearch();
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("field1","value1");

System.out.println(termQueryBuilder.toString());

searchSourceBuilder.query(termQueryBuilder).from(0).size(10);

System.out.println(searchSourceBuilder.toString());

searchRequestBuilder.setSource(searchSourceBuilder);

System.out.println(searchRequestBuilder.toString());
}
}


[Output]

[2018-04-03T13:36:38,466][INFO ][o.e.p.PluginsService     ] [_client_] no modules loaded

[2018-04-03T13:36:38,470][INFO ][o.e.p.PluginsService     ] [_client_] loaded plugin [org.elasticsearch.index.reindex.ReindexPlugin]

[2018-04-03T13:36:38,470][INFO ][o.e.p.PluginsService     ] [_client_] loaded plugin [org.elasticsearch.join.ParentJoinPlugin]

[2018-04-03T13:36:38,470][INFO ][o.e.p.PluginsService     ] [_client_] loaded plugin [org.elasticsearch.percolator.PercolatorPlugin]

[2018-04-03T13:36:38,470][INFO ][o.e.p.PluginsService     ] [_client_] loaded plugin [org.elasticsearch.script.mustache.MustachePlugin]

[2018-04-03T13:36:38,470][INFO ][o.e.p.PluginsService     ] [_client_] loaded plugin [org.elasticsearch.transport.Netty4Plugin]

{

  "term" : {

    "field1" : {

      "value" : "value1",

      "boost" : 1.0

    }

  }

}

{"from":0,"size":10,"query":{"term":{"field1":{"value":"value1","boost":1.0}}}}

{"from":0,"size":10,"query":{"term":{"field1":{"value":"value1","boost":1.0}}}}


Process finished with exit code 0



Trackback 0 : Comment 0

[Elasticsearch] elasticsearch-analysis-arirang 버그 수정

Elastic/Elasticsearch 2018.01.30 11:01

몇 가지 오류와 누락 된 기능이 있어서 추가해서 릴리즈 했습니다.

1. StartOffset 과 EndOffset 정보에 대한 order 가 깨져서 에러가 나는 부분이 있었는데 수정해서 올렸습니다.

2. REST Action API 하나 누락 되어서 추가해서 올렸습니다.


https://github.com/HowookJeong/elasticsearch-analysis-arirang/releases


Trackback 0 : Comment 0