'아리랑'에 해당되는 글 10건

  1. 2018.06.28 [Elasticsearch] HighLevelRestClient 를 이용한 Bulk Indexing 로컬 테스트 결과
  2. 2017.11.15 [Elasticsearch] elasticsearch-arirang-analyzer-6.0.0 릴리즈
  3. 2017.10.19 [Elasticsearch] Arirang Analyzer + Elasticsearch Analyzer Plugin 사용자 관점 개발리뷰
  4. 2017.06.23 [Arirang] 사전 기반으로만 형태소 분석 처리 해보기
  5. 2017.04.27 [Elasticsearch] 5.x 용 Arirang 형태소 분석기 사용 시 주의 사항.
  6. 2016.11.25 [Elasticsearch] elasticsearch-analysis-arirang 5.0.1 플러그인 개발기
  7. 2016.11.24 [Elasticsearch] Lucene Arirang Analyzer Plugin for Elasticsearch 5.0.1
  8. 2016.03.17 [Elasticsearch] Elasticsearch에 Arirang 외부 사전 등록하기
  9. 2015.11.20 [arirang] 사전 데이터 등록 예제
  10. 2015.11.10 [Elasticsearch] arirang analyzer offset 추출 오류.

[Elasticsearch] HighLevelRestClient 를 이용한 Bulk Indexing 로컬 테스트 결과

Elastic/Elasticsearch 2018. 6. 28. 11:35


arirang plug 을 적용해서 돌려본 실행 속도 입니다.


[DEBUG] 2018-07-02 13:12:18.407 [main] MainIndexer - Bulk operation elapsed time [811.0869750976562] sec

[DEBUG] 2018-07-02 13:14:16.595 [main] MainIndexer - Force merge operation elapsed time [118.18800354003906] sec


[Settings]

"settings":{
"number_of_shards":1,
"number_of_replicas":0,
"index.refresh_interval":"1h",
"index.routing.allocation.require.box_type":"indexing",
"index.similarity.default.type":"BM25",
"index":{
"analysis":{
"analyzer":{
"arirang_custom_analyzer":{
"tokenizer":"arirang_tokenizer",
"filter":[
"lowercase",
"trim",
"custom_synonym",
"arirang_filter"
]
}
},
"filter":{
"custom_synonym":{
"type":"synonym_graph",
"synonyms":[]
}
}
}
}
}


[Mappings]

"mappings" : {
"_doc": {
"_source": {
"enabled": true
},
"dynamic_templates": [
{
"strings": {
"match_mapping_type": "string",
"mapping": {
"type": "text",
"analyzer": "arirang_custom_analyzer",
"fields": {
"raw": {
"type": "keyword",
"ignore_above": 50
}
}
}
}
}
]
}
}





얼마전 밋업에서 김종민님이 공유해 주신 위키피디아 문서를 가지고 테스트한 결과 입니다.

그냥 제가 만든 Indexer 모듈에 대한 성능 테스트용도로 한번 실험 삼아 돌려 본거라 별 도움이 안될 수 있습니다.


아래 문서는 언제까지 올라가 있을지 모르겠습니다.

빨리 받으시면 될 듯 하내요.


문서 다운로드 링크)

https://s3.ap-northeast-2.amazonaws.com/kr.elastic.co/sample-data/kr-wikipedia-dump.json.tar.gz


위키피디아 문서 색인 테스트 결과)

MacBook Pro

CPU 2.8G i7

MEM 16GB

API : HighLevelRestClient

REST API : _bulk

Settings

primary shard : 1

replica shard : 0

refresh_interval : 1h

similarity : BM25

default analyzer (standard)

Mappings

dynamic mapping

Indexing File Source Size 

3.6GB

Indexing Segment File Size (force merge 전)

11 GB

Indexing Segment File Size (force merge 후)

4.28 GB

Bulk Request Thread Size

5

Bulk Request Document Size (per thread)

500

Bulk Indexing / Force Merge Time

[DEBUG] 2018-06-28 11:06:13.780 [main] MainIndexer - Bulk operation elapsed time [366.6780090332031] sec

[DEBUG] 2018-06-28 11:08:22.254 [main] MainIndexer - Force merge operation elapsed time [128.47300720214844] sec

Indexing Documents

Total indexed document are 1020662


결과적으로 튜닝한 내용은 전혀 없고 그냥 색인기 기능 테스트 정도로 보셔도 될 것 같습니다.


:

[Elasticsearch] elasticsearch-arirang-analyzer-6.0.0 릴리즈

Elastic/Elasticsearch 2017. 11. 15. 23:49

페북에 올렸더니 스팸 이라고 삭제 당했내요. ㅡ.ㅡ;

https://github.com/HowookJeong/elasticsearch-analysis-arirang/tree/6.0.0

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


설치 방법은 잘 아시겠지만 두 가지 입니다.

$ bin/elasticsearch-plugin install file:///elasticsearch-analysis-arirang-6.0.0.zip

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


적용된 version 은 아래와 같습니다.

elasticsearch-6.0.0

lucene-7.0.1

arirang.lucene-analyzer-7.0.1

arirang.morph-1.1.0


혹시 arirang plugin 을 어떻게 만드는지 궁금하신 분들은 아래 글 참고하세요.

[Elasticsearch] Arirang Analyzer + Elasticsearch Analyzer Plugin 사용자 관점 개발리뷰


:

[Elasticsearch] Arirang Analyzer + Elasticsearch Analyzer Plugin 사용자 관점 개발리뷰

Elastic/Elasticsearch 2017. 10. 19. 14:25

사용자 관점에서 어떻게 개발 하는지 정리해 보았습니다.


Elasticsearch를 서비스에 사용하면서 한글 처리를 위해 어떤 analyzer를 사용해야 할지 고민해 보신적이 있을 것입니다.

오늘은 제가 사용하고 있는 Lucene Korean Analyzer와 이를 Elasticsearch에 plugin으로 설치하고 사용하는 방법을 알아 보도록 하겠습니다.


들어 가기에 앞서 lucene에서 제공하는 analyzer의 기본 구성과 동작에 대해서 살펴 보겠습니다.

Lucene에서 제공하는 analyzer 는 하나의 tokenizer와 다수의 filter로 구성이 됩니다.

Filter 는 CharFilter와 TokenFilter 두 가지가 있습니다.

CharFilter는 입력된 문자열에서 불필요한 문자를 normalization 하기 위해 사용되며 TokenFilter는 tokenizer에 의해 분해된 token에 대한 filter 처리를 하게 됩니다.

결과적으로 아래와 같은 순서로 analysis 된다고 이해 하면 됩니다.


Input Text 

Character Filter    Filtered Text        

Tokenizer              Tokens                 →

Token Filter          Filtered Tokens   

Output Tokens


이제 본론으로 들어 가겠습니다.

Lucene Korean Analyzer는 현재 이수명님에 의해 개발 및 유지보수가 되고 있으며 오픈소스로 등록이 되어 있습니다.

관련 소스코드는 아래 두 가지 repository를 통해서 제공 되고 있습니다.


[svn 주소]

https://lucenekorean.svn.sourceforge.net/svnroot/lucenekorean


[github 주소]

https://github.com/korlucene


 Lucene Korean Analyzer 는 지금 Arirang 이라고 부르고 있습니다.


Arirang의 프로젝트 구성은 크게 두 부분으로 나뉩니다.

  • arirang analyzer
  • arirang morph


1. arirang morph

  이 프로젝트는 한글 형태소에 대한 기본 분석과 사전 정보로 구성이 되어 있습니다.

  한글 처리와 사전 정보를 변경 하고 싶을 경우 본 프로젝트의 코드를 분석하고 수정 해서 활용을 하실 수 있습니다.


2. arirang analyzer

  이 프로젝트는 lucene의 analyzer를 상속받아 lucene에서 사용 할 수 있도록 구성이 되어 있습니다.

  Lucene의 analyzer pipeline에 필요한 

    - KoreanAnalyzer

    - KoreanFilter

    - KoreanFilterFactory

    - KoreanToken

    - KoreanTokenizer

    - KoreanTokenizerFactory

  등이 주요 클래스로 구현이 되어 있습니다.


한글 형태소 분석에서 중요한 역할을 하는 부분으로 사전 이라는 것이 있으며, 이를 알아 보도록 하겠습니다.

arirang.morph 프로젝트에 포함이 되어 있으며 언급 한것과 같이 지속적인 업데이트 및 변경이 가능 합니다.


1. Dictionary classpath

  org/apache/lucene/analysis/ko/dic


2. Dictionary files

  org/apache/lucene/analysis/ko

    korean.properties

  org/apache/lucene/analysis/ko/dic

    abbreviation.dic

    cj.dic

    compounds.dic

    eomi.dic

    extension.dic

    josa.dic

    mapHanja.dic

    occurrence.dic

    prefix.dic

    suffix.dic

    syllable.dic

    total.dic

    uncompounds.dic


3. 주요 사전 설명

주요 사전 설명 이라고는 했지만 쉽고 빠르게 활용할 수 있는 사전이라고 이해 하시면 좋을 것 같습니다.

  • total.dic
    이 사전 파일은 arirang analyzer 에서 사용하는 기본 사전으로 그대로 사용을 하시면 됩니다.
    다만, 수정이 필요 하실 경우 아래 extension.dic 파일을 활용 하시면 됩니다.
  • extension.dic
    확장사전이라고 부르며, 사전 데이터를 추가 해야 할 경우 이 파일에 추가해서 운영 및 관리를 하시면 됩니다.
  • compounds.dic
    복합명사 사전으로 하나의 단어가 여러개의 단어로 구성이 되어 있을 경우 이를 분해하기 위한 사전 정보를 관리 하는 파일 입니다.


4. total.dic / extension.dic 파일 구조

체언 용언 기타품사 하여(다)동사 되어(다)동사 '내'가붙을수있는체언 NA NA NA 불규칙변경


예)

  # 엘사는 명사이고 동사, 기타품사, 불규칙이 아니다, 라고 가정하면 아래와 같이 표현이 됩니다.

  엘사,100000000X


  # 노래는 명사이고 하여(다) 동사가 됩니다.

  노래,100100000X


  # 소리는 명사이고 소리내다와 같이 내가 붙을 수 있는 명사 입니다.

  소리,100001000X


불규칙 정보는 아래와 같으며 원문을 참고 하시기 바랍니다.

  B : ㅂ 불규칙

  H : ㅎ 불규칙

  L : 르 불규칙

  U : ㄹ 불규칙

  S : ㅅ 불규칙

  D : ㄷ 불규칙

  R : 러 불규칙

  X : 규칙

 원문 : http://cafe.naver.com/korlucene/135


5. compound.dic 파일 구조

분해전단어:분해후단어1,분해후단어2,...,분해후단어N:DBXX


분해전단어에 하여(다)동사(D), 되어(다)동사(B) 가 붙을 수 있는지 확인 하셔야 합니다.


예)

  객관화:객관,화:1100


  이와 같이 된 이유는

    객관화하다

    객관화되다

  가 되기 때문입니다.


  참고)

  http://krdic.naver.com/search.nhn?query=%EA%B0%9D%EA%B4%80%ED%99%94&kind=all


이제 부터는 소스 코드를 내려 받아서 빌드 후 Elasticsearch plugin을 만드는 방법을 알아 보겠습니다.


1. 프로젝트 clone

기본적으로 master branch 를 받습니다.


$ git clone https://github.com/korlucene/arirang.morph.git

$ git clone https://github.com/korlucene/arirang-analyzer-6.git


2. Maven build

  • 두 프로젝트 모드 maven project로 빌드 장비에 maven 이 설치가 되어 있어야 합니다.
    maven 설치 참고 - https://maven.apache.org/
  • arirang-analyzer-6 프로젝트에 기본적으로 arirang.morph 패키지가 등록이 되어 있기 때문에 별도 arirang.morph를 수정 하지 않았다면 arirang-analyzer-6 만 빌드하시면 됩니다.


arirang.morph $ mvn clean package

arirang-analyzer-6 $ mvn clean package


3. 기능 테스트

  • 기능 테스트는 arirang-analyzer-6 프로젝트에 포함된 test code를 이용해서 확인해 보시면 됩니다.
  • src/test 아래 TestKoreanAnalyzer1 클래스를 참고하시면 됩니다.

 아래는 이해를 돕기 위해 원본 테스트 코드를 추가 하였습니다.

/**

 * Created by SooMyung(soomyung.lee@gmail.com) on 2014. 7. 30.

 */

public class TestKoreanAnalyzer1 extends TestCase {


  public void testKoreanAnalzer() throws Exception {


    String[] sources = new String[]{

      "고려 때 중랑장(中郞將) 이돈수(李敦守)의 12대손이며",

      "이돈수(李敦守)의",

      "K·N의 비극",

      "金靜子敎授",

      "天國의",

      "기술천이",

      "12대손이며",

      "明憲淑敬睿仁正穆弘聖章純貞徽莊昭端禧粹顯懿獻康綏裕寧慈溫恭安孝定王后",

      "홍재룡(洪在龍)의",

      "정식시호는 명헌숙경예인정목홍성장순정휘장소단희수현의헌강수유령자온공안효정왕후(明憲淑敬睿仁正穆弘聖章純貞徽莊昭端禧粹顯懿獻康綏裕寧慈溫恭安孝定王后)이며 돈령부영사(敦寧府領事) 홍재룡(洪在龍)의 딸이다. 1844년, 헌종의 정비(正妃)인 효현왕후가 승하하자 헌종의 계비로써 중궁에 책봉되었으나 5년 뒤인 1849년에 남편 헌종이 승하하고 철종이 즉위하자 19세의 어린 나이로 대비가 되었다. 1857년 시조모 대왕대비 순원왕후가 승하하자 왕대비가 되었다.",

      "노벨상을"

    };


    KoreanAnalyzer analyzer = new KoreanAnalyzer();


    for (String source : sources) {

      TokenStream stream = analyzer.tokenStream("dummy", new StringReader(source));


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

      PositionIncrementAttribute posIncrAtt = stream.addAttribute(PositionIncrementAttribute.class);

      PositionLengthAttribute posLenAtt = stream.addAttribute(PositionLengthAttribute.class);

      TypeAttribute typeAtt = stream.addAttribute(TypeAttribute.class);

      OffsetAttribute offsetAtt = stream.addAttribute(OffsetAttribute.class);

      MorphemeAttribute morphAtt = stream.addAttribute(MorphemeAttribute.class);

      stream.reset();


      while (stream.incrementToken()) {

        System.out.println(termAtt.toString() + ":" + posIncrAtt.getPositionIncrement() + "(" + offsetAtt.startOffset() + "," + offsetAtt.endOffset() + ")");

      }

      stream.close();

    }


  }

}


이제 arirang에 대한 빌드와 기능테스트가 끝났으니 elasticsearch에 설치 하기 위한 plugin 만드는 방법을 알아 보도록 하겠습니다.

먼저, elasticsearch에서 제공하는 plugins 관련 문서를 시간이 된다면 한번 읽어 보시고 아래 내용을 보시길 추천 드립니다.


Elasticsearch Plugins and Integrations : https://www.elastic.co/guide/en/elasticsearch/plugins/5.5/index.html


Elastic에서 공식문서에서 제공해 주고 있는 예제는 아래 링크에 나와 있으니 구현 시 참고하시기 바랍니다.

 https://github.com/elastic/elasticsearch/tree/master/plugins/jvm-example


 제가 추천하는 것은 elasticsearch source code를 다운받아 official하게 작성된 plugin 코드를 참고하여 구현하는 방법 입니다.


그럼 analysis plugin의 기본 프로젝트 구조를 살펴 보겠습니다.


1. Project Directory

  src/main

  assemblies

    plugin.xml

  java

    org/elasticsearch

      index/analysis

        ${CUSTOM-ANALYZER-NAME}AnalyzerProvider

        ${CUSTOM-ANALYZER-NAME}TokenFilterFactory

        ${CUSTOM-ANALYZER-NAME}TokenizerFactory

      plugin/analysis/arirang

        Analysis${CUSTOM-ANALYZER-NAME}Plugin

  resources

    plugin-descriptor.propeties


2. Files and classes

  • plugin.xml
      maven assembly plugin을 이용한 패키징을 하기 위한 설정을 구성 합니다.
  • plugin-descriptor.propeties
      plugin authors 정보를 구성 합니다.
      elasticsearch reference) https://www.elastic.co/guide/en/elasticsearch/plugins/5.5/plugin-authors.html
  • ${CUSTOM-ANALYZER-NAME}AnalyzerProvider
      custom analyzer 생성자 제공을 위한 코드를 작성 합니다.
  • ${CUSTOM-ANALYZER-NAME}TokenFilterFactory
      custom filter 생성자 제공을 위한 코드를 작성 합니다.
  • ${CUSTOM-ANALYZER-NAME}TokenizerFactory
      custom tokenizer 생성자 제공을 위한 코드를 작성 합니다.
  • Analysis${CUSTOM-ANALYZER-NAME}Plugin
      custom analyzer plugin 등록을 위한 코드를 작성 합니다.

이와 같은 구조를 이용하여 elasticsearch-analysis-arirang plugin을 만들어 보도록 하겠습니다.

본 plugin에서는 arirang에서 제공하는 dynamic dictionary reload 기능을 사용하기 위한 Rest Handler도 추가해서 만들어 보도록 하겠습니다.


소스코드 참고)

https://github.com/HowookJeong/elasticsearch-analysis-arirang/tree/5.5.0


Step1)

Step2)

  • Plugin project structure를 구성 합니다.

Step3)

  • root path에 lib 폴더를 생성하고 arirang analyzer 관련 jar 파일을 복사해 놓습니다.
  • arirang.lucene-analyzer-VERSION.jar
  • arirang-morph-VERSION.jar

Step4)

  • pom.xml에서 local jar 파일에 대한 dependency 설정을 추가해 줍니다.

    <dependency>

      <groupId>com.argo</groupId>

      <artifactId>morph</artifactId>

      <version>${morph.version}</version>

      <scope>system</scope>

      <systemPath>${project.basedir}/lib/arirang-morph-${morph.version}.jar</systemPath>

      <optional>false</optional>

    </dependency>


    <dependency>

      <groupId>com.argo</groupId>

      <artifactId>arirang.lucene-analyzer-${lucene.version}</artifactId>

      <version>${morph.version}</version>

      <scope>system</scope>

      <systemPath>${project.basedir}/lib/arirang.lucene-analyzer-${lucene.version}-${morph.version}.jar</systemPath>

      <optional>false</optional>

    </dependency>


Step5)

  • analysis plugin 관련 코드를 작성 합니다.

    @Override

    public List<RestHandler> getRestHandlers(Settings settings, RestController restController, ClusterSettings clusterSettings,

      IndexScopedSettings indexScopedSettings, SettingsFilter settingsFilter, IndexNameExpressionResolver indexNameExpressionResolver,

      Supplier<DiscoveryNodes> nodesInCluster) {

        return singletonList(new ArirangAnalyzerRestAction(settings, restController));

    }


    @Override

    public Map<String, AnalysisProvider<TokenFilterFactory>> getTokenFilters() {

        return singletonMap("arirang_filter", ArirangTokenFilterFactory::new);

    }


    @Override

    public Map<String, AnalysisProvider<TokenizerFactory>> getTokenizers() {

        Map<String, AnalysisProvider<TokenizerFactory>> extra = new HashMap<>();

        extra.put("arirang_tokenizer", ArirangTokenizerFactory::new);


        return extra;

    }


    @Override

    public Map<String, AnalysisProvider<AnalyzerProvider<? extends Analyzer>>> getAnalyzers() {

        return singletonMap("arirang_analyzer", ArirangAnalyzerProvider::new);

    }


Step6)

  • analysis 관련 코드를 작성 합니다.

    // ArirangAnalyzerProvider

    private final KoreanAnalyzer analyzer;


    public ArirangAnalyzerProvider(IndexSettings indexSettings, Environment env, String name, Settings settings) throws IOException {

        super(indexSettings, name, settings);


        analyzer = new KoreanAnalyzer();

    }


    @Override

    public KoreanAnalyzer get() {

        return this.analyzer;

    }


    // ArirangTokenFilterFactory

    public ArirangTokenFilterFactory(IndexSettings indexSettings, Environment env, String name, Settings settings) {

        super(indexSettings, name, settings);

    }


    @Override

    public TokenStream create(TokenStream tokenStream) {

        return new KoreanFilter(tokenStream);

    }


    // ArirangTokenizerFactory

    public ArirangTokenizerFactory(IndexSettings indexSettings, Environment env, String name, Settings settings) {

        super(indexSettings, name, settings);

    }


    @Override

    public Tokenizer create() {

        return new KoreanTokenizer();

    }


Step7)

  • rest action 관련 코드를 작성 합니다.

  // ArirangAnalyzerRestAction

  @Inject

  public ArirangAnalyzerRestAction(Settings settings, RestController controller) {

    super(settings);


    controller.registerHandler(RestRequest.Method.GET, "/_arirang_dictionary_reload", this);

  }


  @Override

  protected RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient client) throws IOException {

    try {

      DictionaryUtil.loadDictionary();

    } catch (MorphException me) {

      return channel -> channel.sendResponse(new BytesRestResponse(RestStatus.NOT_ACCEPTABLE, "Failed which reload arirang analyzer dictionary!!"));

    } finally {

    }


    return channel -> channel.sendResponse(new BytesRestResponse(RestStatus.OK, "Reloaded arirang analyzer dictionary!!"));

  }


  // ArirangAnalyzerRestModule

  @Override

  protected void configure() {

    // TODO Auto-generated method stub

    bind(ArirangAnalyzerRestAction.class).asEagerSingleton();

  }


Step8)

  • plugin-descriptor.properties 관련 코드를 작성 합니다.

  classname=org.elasticsearch.plugin.analysis.arirang.AnalysisArirangPlugin

  name=analysis-arirang

  jvm=true

  java.version=1.8

  site=false

  isolated=true

  description=Arirang plugin

  version=${project.version}

  elasticsearch.version=${elasticsearch.version}

  hash=${buildNumber}

  timestamp=${timestamp}


Step9)

  • 패키징을 하기 위한 plugin.xml 관련 코드를 작성 합니다.

    <file>

      <source>lib/arirang.lucene-analyzer-6.5.1-1.1.0.jar</source>

      <outputDirectory>elasticsearch</outputDirectory>

    </file>

    <file>

      <source>lib/arirang-morph-1.1.0.jar</source>

      <outputDirectory>elasticsearch</outputDirectory>

    </file>

    <file>

      <source>target/elasticsearch-analysis-arirang-5.5.0.jar</source>

      <outputDirectory>elasticsearch</outputDirectory>

    </file>

    <file>

      <source>${basedir}/src/main/resources/plugin-descriptor.properties</source>

      <outputDirectory>elasticsearch</outputDirectory>

      <filtered>true</filtered>

    </file>


Step10)

  • 빌드를 합니다.

  $ mvn clean package -DskipTests=true


여기서는 작성된 코드는 일부만 발췌 했기 때문에 github에 올라간 소스코드를 참고하시기 바랍니다.

또한, 위 단계는 순서가 중요한 것이 아니며 구성과 어떻게 구현을 해야 하는지를 이해 하시는게 중요 합니다.


이제 빌드가 완료 되었으니 설치 및 기능 점검을 수행해 보도록 하겠습니다.


1. 설치

$ bin/elasticsearch-plugin install --verbose file:///path/elasticsearch-analysis-arirang-5.5.0.zip


2. 기능점검

  • 실행

$ bin/elasticsearch

[2017-08-22T18:56:17,223][INFO ][o.e.n.Node               ] [singlenode] initializing ...

[2017-08-22T18:56:17,289][INFO ][o.e.e.NodeEnvironment    ] [singlenode] using [1] data paths, mounts [[/ (/dev/disk1)]], net usable_space [489.3gb], net total_space [930.3gb], spins? [unknown], types [hfs]

[2017-08-22T18:56:17,289][INFO ][o.e.e.NodeEnvironment    ] [singlenode] heap size [1.9gb], compressed ordinary object pointers [true]

[2017-08-22T18:56:17,309][INFO ][o.e.n.Node               ] [singlenode] node name [singlenode], node ID [saCA_25vSxyUwF-RagteLw]

[2017-08-22T18:56:17,309][INFO ][o.e.n.Node               ] [singlenode] version[5.5.0], pid[12613], build[260387d/2017-06-30T23:16:05.735Z], OS[Mac OS X/10.12.5/x86_64], JVM[Oracle Corporation/Java HotSpot(TM) 64-Bit Server VM/1.8.0_72/25.72-b15]

[2017-08-22T18:56:17,309][INFO ][o.e.n.Node               ] [singlenode] JVM arguments [-Xms2g, -Xmx2g, -XX:+UseConcMarkSweepGC, -XX:CMSInitiatingOccupancyFraction=75, -XX:+UseCMSInitiatingOccupancyOnly, -XX:+DisableExplicitGC, -XX:+AlwaysPreTouch, -Xss1m, -Djava.awt.headless=true, -Dfile.encoding=UTF-8, -Djna.nosys=true, -Djdk.io.permissionsUseCanonicalPath=true, -Dio.netty.noUnsafe=true, -Dio.netty.noKeySetOptimization=true, -Dio.netty.recycler.maxCapacityPerThread=0, -Dlog4j.shutdownHookEnabled=false, -Dlog4j2.disable.jmx=true, -Dlog4j.skipJansi=true, -XX:+HeapDumpOnOutOfMemoryError, -Des.path.home=/Users/jeonghoug/dev/server/elastic/elasticsearch-5.5.0]

[2017-08-22T18:56:18,131][INFO ][o.e.p.PluginsService     ] [singlenode] loaded module [aggs-matrix-stats]

[2017-08-22T18:56:18,131][INFO ][o.e.p.PluginsService     ] [singlenode] loaded module [ingest-common]

[2017-08-22T18:56:18,131][INFO ][o.e.p.PluginsService     ] [singlenode] loaded module [lang-expression]

[2017-08-22T18:56:18,131][INFO ][o.e.p.PluginsService     ] [singlenode] loaded module [lang-groovy]

[2017-08-22T18:56:18,131][INFO ][o.e.p.PluginsService     ] [singlenode] loaded module [lang-mustache]

[2017-08-22T18:56:18,131][INFO ][o.e.p.PluginsService     ] [singlenode] loaded module [lang-painless]

[2017-08-22T18:56:18,131][INFO ][o.e.p.PluginsService     ] [singlenode] loaded module [parent-join]

[2017-08-22T18:56:18,131][INFO ][o.e.p.PluginsService     ] [singlenode] loaded module [percolator]

[2017-08-22T18:56:18,131][INFO ][o.e.p.PluginsService     ] [singlenode] loaded module [reindex]

[2017-08-22T18:56:18,132][INFO ][o.e.p.PluginsService     ] [singlenode] loaded module [transport-netty3]

[2017-08-22T18:56:18,132][INFO ][o.e.p.PluginsService     ] [singlenode] loaded module [transport-netty4]

[2017-08-22T18:56:18,132][INFO ][o.e.p.PluginsService     ] [singlenode] loaded plugin [analysis-arirang]

[2017-08-22T18:56:19,195][INFO ][o.e.d.DiscoveryModule    ] [singlenode] using discovery type [zen]

[2017-08-22T18:56:19,686][INFO ][o.e.n.Node               ] [singlenode] initialized

[2017-08-22T18:56:19,687][INFO ][o.e.n.Node               ] [singlenode] starting ...

[2017-08-22T18:56:24,837][INFO ][o.e.t.TransportService   ] [singlenode] publish_address {127.0.0.1:9300}, bound_addresses {[fe80::1]:9300}, {[::1]:9300}, {127.0.0.1:9300}

[2017-08-22T18:56:27,899][INFO ][o.e.c.s.ClusterService   ] [singlenode] new_master {singlenode}{saCA_25vSxyUwF-RagteLw}{_fn1si8zTT6bkZK1q6ilxQ}{127.0.0.1}{127.0.0.1:9300}, reason: zen-disco-elected-as-master ([0] nodes joined)

[2017-08-22T18:56:27,928][INFO ][o.e.h.n.Netty4HttpServerTransport] [singlenode] publish_address {127.0.0.1:9200}, bound_addresses {[fe80::1]:9200}, {[::1]:9200}, {127.0.0.1:9200}

[2017-08-22T18:56:27,928][INFO ][o.e.n.Node               ] [singlenode] started


  • 형태소분석기 확인

http://localhost:9200/_analyze?pretty&analyzer=arirang_analyzer&text=한국 엘라스틱서치 사용자 그룹의 HENRY 입니다.


  • 형태소분석기 결과 확인

{

  "tokens" : [

    {

      "token" : "한국",

      "start_offset" : 0,

      "end_offset" : 2,

      "type" : "korean",

      "position" : 0

    },

    {

      "token" : "엘라스틱서치",

      "start_offset" : 3,

      "end_offset" : 9,

      "type" : "korean",

      "position" : 1

    },

    {

      "token" : "엘라",

      "start_offset" : 3,

      "end_offset" : 5,

      "type" : "korean",

      "position" : 1

    },

    {

      "token" : "스틱",

      "start_offset" : 5,

      "end_offset" : 7,

      "type" : "korean",

      "position" : 2

    },

    {

      "token" : "서치",

      "start_offset" : 7,

      "end_offset" : 9,

      "type" : "korean",

      "position" : 3

    },

    {

      "token" : "사용자",

      "start_offset" : 10,

      "end_offset" : 13,

      "type" : "korean",

      "position" : 4

    },

    {

      "token" : "그룹",

      "start_offset" : 14,

      "end_offset" : 16,

      "type" : "korean",

      "position" : 5

    },

    {

      "token" : "henry",

      "start_offset" : 18,

      "end_offset" : 23,

      "type" : "word",

      "position" : 6

    },

    {

      "token" : "입니다",

      "start_offset" : 24,

      "end_offset" : 27,

      "type" : "korean",

      "position" : 7

    }

  ]

}


  • 형태소분석기 RESTful endpoint 실행 및 결과

  실행)

    http://localhost:9200/_arirang_dictionary_reload


  결과)

    Reloaded arirang analyzer dictionary!!


이제 기본적인 arirang analyzer와 elasticsearch용 plugin 까지 살펴 보았습니다.

마지막으로 arirang analyzer의 사전 데이터 수정과 반영을 살펴 보겠습니다.


 arirang 에서 제공하는 기본 dictionary path 변경을 하지 않고 사전 내용만 변경 하는 것으로 하겠습니다.


1. 사전 파일에 대한 classpath 설정

  • elasticsearch 실행 시 사전 파일에 대한 classpath 등록이 되어 있어야 정상적으로 로딩이 됩니다.
  • elasticsearch.in.sh 파일을 수정해 줍니다.

  ES_CLASSPATH="$ES_HOME/lib/elasticsearch-5.5.0.jar:$ES_HOME/lib/*:$ES_CONF_PATH/dictionary"


  예) 위에서 언급한 사전 관련 path와 파일들이 존재해야 합니다.

    config/dictionary/org/apache/lucene/analysis/ko

    config/dictionary/org/apache/lucene/analysis/ko/dic

  • ES_CONF_PATH는 기본 path.conf 정보와 동일해야 합니다.


2. 사전 정보 수정 및 반영

  • 1번 path에 위치한 사전 파일을 수정합니다.


3. 사전 reload

  • elasticsearch restart 없이 /_arirang_dictionary_reload API를 호출하여 반영 합니다.


여기까지 오셨으면 이제 arirang analyzerelasticseearch-analysis-arirang plugin 그리고 dictionary에 대한 기본 활용을 하실수 있게 되셨다고 생각합니다.

기술된 모든 정보는 모두 오픈소스이기 때문에 출처를 정확히 명시해 주시고 언제든지 오류와 개선에 대해서는 적극적인 참여 부탁 드립니다.


참고 사이트)

http://cafe.naver.com/korlucene

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

https://www.elastic.co/guide/en/elasticsearch/plugins/current/index.html

:

[Arirang] 사전 기반으로만 형태소 분석 처리 해보기

ITWeb/검색일반 2017. 6. 23. 13:51

그냥 사전만 가지고 몇 가지 형태소 분석 처리를 하기 위한 팁 정보 입니다.

한마디로 노가다 입니다.

모든 부분에 공통적으로 적용 되는 것은 아니며 사용 형태에 따라 수정 하셔야 하는 부분이니 그냥 참고 정도만 하자라고 생각해 주세요.


공통)

- 복합명사 분해 시 분해 된 단어가 용언일 경우 복합명사를 사용하지 말고 확장사전에 등록해서 사용을 합니다.

  또는 분해 된 단어가 용언일 경우 찾아서 체언 처리를 해줍니다.

- 체언과 기타품사 차이는 체언은 단독으로 사용 시 형태소 분석이 되지만 기타품사는 분석 되지 않습니다.


  복합명사)

    그리는게:그리는,게:0000


  확장사전)

    그리,100000000X

    그리는게,100000000X


  분해)

    그리는게

      그리는게

    그리는

      그리


'그리는' 자체를 체언으로 분해 하고 싶을 경우 확장 사전에 체언으로 등록이 되어야 하며, 그리에 대한 용언도 동일하게 체언처리가 되어야 합니다.



- '~요', '~해요' 로 끝나는 용언 처리

  좋아요

  좋아해요


  확장사전)

    좋아,100000000X

    좋아해,100000000X



- '~져', '~져서', '~서' 로 끝나는 용언 처리

  기존 용언으로 등록된 단어를 체언으로 변경 해야 합니다.

  010000000X -> 100000000X

  '~서' 의 경우 사전에 '서,110000000X' 와 같이 등록이 되어 있어 복합명사 사전에 추가 등록을 합니다.

  복합명사 등록 시 분해된 명사에 대한 확장사전 등록이 되어 있어야 합니다.


  확장사전)

    어두워지,100000000X

    어두워,100000000X

    늘어지,100000000X

    늘어져,100000000X


  복합명사)

    어두워서:어두워서,어두워:0000

    어두워져:어두워져,어두워:0000

    어두워져서:어두워져서,어두워:0000

    늘어져서:늘어져서,늘어져:0000



- 복합용언 + '~요' 로 끝나는 용언 처리

  크고낮아요

  말려들어요


  복합명사)

    크고낮아:크고,낮아:0000

    말려들어:말려,들어:0000



- '~다', '~데' 로 끝나는 용언 처리

  크다

  작다

  큰데

  작은데

  '~다' 끝나는 용언이 형태소분리가 되기 위해서는 확장사전에 등록이 되어야 합니다.


  확장사전)

    크다,100000000X

    작다,100000000X

    큰데,100000000X

    작은데,100000000X

  


- '~ㄴ', '~은', '~는' 으로 끝나는 용언 처리

  짧은

  넒은

  튀어나온

  어울리는

    어울리,010000000X 용언 처리가 되어 있기 때문에 체언으로 fully 등록 합니다.

  잃어가는


  확장사전)

    짧은,100000000X

    넓은,100000000X

    튀어나온,100000000X

    잃어가는,100000000X

    어울리는,100000000X



- 'ㅎ' 불규칙 용언 처리

  노랗고

  동그랗고


  확장사전)

    노랗,100000000X


  복합명사)

    노랗고:노랗고,노랗:0000


- '~하', '~한' 으로 끝나는 용언 처리

  확장사전에 용언 처리가 되어 있는지 확인 합니다.

  용언 처리가 되어 있다면 체언으로 변경해 줍니다.

  확장사전에 ~하, ~한 을 제외 및 하다 동사 표기를 포함한 체언으로 등록 합니다.


  확장사전 1)

    넓적하,010000000X -> 100000000X

    넓적,100100000X

:

[Elasticsearch] 5.x 용 Arirang 형태소 분석기 사용 시 주의 사항.

Elastic/Elasticsearch 2017. 4. 27. 10:05

Elasticsearch에서 아리랑 형태소분석기 사용 시 주의사항)

사실 주의 사항 이라기 보다 1음절 처리에 대한 고민을 해보시면 좋을 것 같다는 의견 드립니다.


2.x 에서 사용하던 arirang 과 lucene 의 버전은 

- morph 1.0.x

- arirang & lucene 5.x

입니다.


5.x 에서 사용하던 arirang 과 lucene 의 버전은

- morph 1.1.0

- arirang & lucene 6.x

입니다.


여기서 arirang morph 쪽 코드가 많이 개선 또는 변경이 되었습니다.

그리고 몇 가지 default 설정 값들에 대한 변화도 있는데요.


제가 발견한 대표적인 문제는 아래와 같습니다.


'울퉁불퉁한' 이라는 source 에 대한 analysis 시 발생을 합니다.


5.x 에서 analyze 한 결과는 아래와 같습니다.

울퉁불퉁한(N)/90:2

울퉁불퉁/Z

한/N

울퉁불퉁(N),하(t),ㄴ(e)/70:2

울퉁/N

불퉁/N


2.x 에서 analyze 한 결과는 아래와 같습니다.

울퉁불퉁(N),하(t),ㄴ(e)/70:2

울퉁/N

불퉁/N


이게 무슨 문제가 되느냐고 할 수 있는데

실제 색인을 실행 하면 position 정보가 5.x 에서 뒤집혀져 색인 되지 않는 문제를 보실 수 있습니다.


5.x 에서 _analyze 한 결과는 아래와 같습니다.

{

  "tokens" : [

    {

      "token" : "울퉁불퉁한",

      "start_offset" : 0,

      "end_offset" : 5,

      "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" : 4,

      "end_offset" : 5,

      "type" : "korean",

      "position" : 1

    },

    {

      "token" : "불퉁",

      "start_offset" : 2,

      "end_offset" : 4,

      "type" : "korean",

      "position" : 2

    }

  ]

}


2.x 에서 _analyze 한 결과는 아래와 같습니다.

{

  "tokens" : [ {

    "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" : 2,

    "end_offset" : 4,

    "type" : "korean",

    "position" : 1

  } ]

}


보이시나요?

어디가 다르고 문제가 되는지?


해결 방법은 CompoundNounAnalyzer 의 setDivisibleOne 설정을 false 로 하시면 위와 같은 문제를 해결 하실 수 있습니다.

2.x 에서는 KoreanFilter 쪽에 조건문이 있었는데 5.x 에서는 주석 처리가 되어 있더라구요.

또는 이것 저것 다 귀찮다고 하시면 그냥 '한' 에 대한 불용어 처리를 하셔도 될 것 같습니다.

:

[Elasticsearch] elasticsearch-analysis-arirang 5.0.1 플러그인 개발기

Elastic/Elasticsearch 2016. 11. 25. 12:31

Elasticsearch cluster 업그레이드를 위해 먼저 한글형태소 분석기 업그레이드가 필요합니다.

기본적으로 한글형태소 분석기 플러그인을 만들기 위해서는 아래의 내용을 어느 정도는 잘 알고 다룰수 있어야 합니다.


- Elasticsearch

- Lucene

- Arirang


Arirang 은 아래 링크를 통해서 소스와 jar 파일을 구하실 수 있습니다.


최근에 수명님 이외 mgkaki 님이 컨트리뷰션을 해주시고 계신듯 합니다. :)


Lucene & Arirang 변경 사항)

- lucene 6.1 과 6.2 의 패키지 구조가 변경이 되고 클래스도 바뀌었습니다.

- arirang 에서 제공하던 pairmap 관련 버그가 수정되었습니다. (그전에 수정이 되었을수도 있습니다. ^^;)

- lucene 에서 제공 되던 CharacterUtils 가 refactoring 되었습니다.

- arirang 에서 KoreanTokenizer 에 선언된 CharacterUtils 를 변경된 내용에 맞게 고쳐주어야 합니다.


Remove CharacterUtils.getInstance()

CharacterUtils.codePointAt(...) to Character.codePointAt(...)


- arirang 6.2 source를 내려 받으시면 위 변경 내용이 반영 되어 있습니다.

- arirang.morph 1.1.0 을 내려 받으셔야 합니다.


Elasticsearch Plugin 변경 사항)

플러그인 개발 변경 사항은 기본 구조 변경이 많이 되었기 때문에 수정 사항이 많습니다.

보기에 따라서 적을 수도 있지만 판단은 각자의 몫으로 ^^


- arirang.lucene-analyzer 와 arirang-morph 업데이트가 되어야 합니다.

- 기존에 binding 하던 AnalysisBinderProcessor를 사용하지 않습니다.

- 이제는 Plugin, AnalysisPlugin 에서 등록을 진행 합니다.


public class AnalysisArirangPlugin extends Plugin implements AnalysisPlugin {

  @Override

  public Map<String, AnalysisProvider<TokenFilterFactory>> getTokenFilters() {

    return singletonMap("arirang_filter", ArirangTokenFilterFactory::new);

  }


  @Override

  public Map<String, AnalysisProvider<TokenizerFactory>> getTokenizers() {

    Map<String, AnalysisProvider<TokenizerFactory>> extra = new HashMap<>();

    extra.put("arirang_tokenizer", ArirangTokenizerFactory::new);


    return extra;

  }


  @Override

  public Map<String, AnalysisProvider<AnalyzerProvider<? extends Analyzer>>> getAnalyzers() {

    return singletonMap("arirang_analyzer", ArirangAnalyzerProvider::new);

  }

}


- AnalyzerProvider, TokenFilterFactory, TokenizerFactory 내 생성자 argument 가 바뀌었습니다.

IndexSettings indexSettings, Environment env, String name, Settings settings


- assemble 하기 위한 plugin.xml 내 outputDirectory 가 elasticsearch 로 변경이 되었습니다. 

- outputDirectory 가 elasticsearch 로 작성되어 있지 않을 경우 에러가 발생 합니다.


이 정도 변경 하고 나면 이제 빌드 및 설치를 하셔도 됩니다.

이전 글 참고) [Elasticsearch] Lucene Arirang Analyzer Plugin for Elasticsearch 5.0.1


※ 플러그인을 만들면서 우선 lucene 6.1 과 6.2 가 바뀌어서 살짝 당황 했었습니다.

당연히 6.x 간에는 패키지 구조에 대한 변경은 없을거라는 기대를 했었는데 이게 잘못이였던 것 같습니다.

역시 lucene 5.x 에서 6.x 로 넘어 가기 때문에 elasticsearch 5.x 는 많이 바뀌었을 거라는 생각은 했었구요.

그래도 생각했던 것 보다 오래 걸리지는 않았지만 역시 참고할 만한 문서나 자료는 어디에도 없더라구요.

소스 보는게 진리라는건 변하지 않는 듯 싶내요. 작성하고 보니 이게 개발기인지 애매하내요. ^^;


소스코드)

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

:

[Elasticsearch] Lucene Arirang Analyzer Plugin for Elasticsearch 5.0.1

Elastic/Elasticsearch 2016. 11. 24. 19:02

우선 빌드한 플러그인 zip 파일 먼저 공유 합니다.

나중에 작업한 내용에 대해서는 github 에 올리도록 하겠습니다.

요즘 프로젝트며 운영 업무가 너무 많아서 이것도 겨우 겨우 시간 내서 작업 했내요.


elasticsearch-analysis-arirang-5.0.1.zip


설치 방법)

$ bin/elasticsearch-plugin install --verbose file:///elasticsearch-analysis-arirang/target/elasticsearch-analysis-arirang-5.0.1.zip


설치 로그)

-> Downloading file:///elasticsearch-analysis-arirang-5.0.1.zip

Retrieving zip from file:///elasticsearch-analysis-arirang-5.0.1.zip

[=================================================] 100%

- Plugin information:

Name: analysis-arirang

Description: Arirang plugin

Version: 5.0.1

 * Classname: org.elasticsearch.plugin.analysis.arirang.AnalysisArirangPlugin

-> Installed analysis-arirang


Elasticsearch 실행 로그)

$ bin/elasticsearch

[2016-11-24T18:49:09,922][INFO ][o.e.n.Node               ] [] initializing ...

[2016-11-24T18:49:10,083][INFO ][o.e.e.NodeEnvironment    ] [aDGu2B9] using [1] data paths, mounts [[/ (/dev/disk1)]], net usable_space [733.1gb], net total_space [930.3gb], spins? [unknown], types [hfs]

[2016-11-24T18:49:10,084][INFO ][o.e.e.NodeEnvironment    ] [aDGu2B9] heap size [1.9gb], compressed ordinary object pointers [true]

[2016-11-24T18:49:10,085][INFO ][o.e.n.Node               ] [aDGu2B9] node name [aDGu2B9] derived from node ID; set [node.name] to override

[2016-11-24T18:49:10,087][INFO ][o.e.n.Node               ] [aDGu2B9] version[5.0.1], pid[56878], build[080bb47/2016-11-11T22:08:49.812Z], OS[Mac OS X/10.12.1/x86_64], JVM[Oracle Corporation/Java HotSpot(TM) 64-Bit Server VM/1.8.0_72/25.72-b15]

[2016-11-24T18:49:11,335][INFO ][o.e.p.PluginsService     ] [aDGu2B9] loaded module [aggs-matrix-stats]

[2016-11-24T18:49:11,335][INFO ][o.e.p.PluginsService     ] [aDGu2B9] loaded module [ingest-common]

[2016-11-24T18:49:11,335][INFO ][o.e.p.PluginsService     ] [aDGu2B9] loaded module [lang-expression]

[2016-11-24T18:49:11,335][INFO ][o.e.p.PluginsService     ] [aDGu2B9] loaded module [lang-groovy]

[2016-11-24T18:49:11,335][INFO ][o.e.p.PluginsService     ] [aDGu2B9] loaded module [lang-mustache]

[2016-11-24T18:49:11,336][INFO ][o.e.p.PluginsService     ] [aDGu2B9] loaded module [lang-painless]

[2016-11-24T18:49:11,336][INFO ][o.e.p.PluginsService     ] [aDGu2B9] loaded module [percolator]

[2016-11-24T18:49:11,336][INFO ][o.e.p.PluginsService     ] [aDGu2B9] loaded module [reindex]

[2016-11-24T18:49:11,336][INFO ][o.e.p.PluginsService     ] [aDGu2B9] loaded module [transport-netty3]

[2016-11-24T18:49:11,336][INFO ][o.e.p.PluginsService     ] [aDGu2B9] loaded module [transport-netty4]

[2016-11-24T18:49:11,336][INFO ][o.e.p.PluginsService     ] [aDGu2B9] loaded plugin [analysis-arirang]

[2016-11-24T18:49:14,151][INFO ][o.e.n.Node               ] [aDGu2B9] initialized

[2016-11-24T18:49:14,151][INFO ][o.e.n.Node               ] [aDGu2B9] starting ...

[2016-11-24T18:49:14,377][INFO ][o.e.t.TransportService   ] [aDGu2B9] publish_address {127.0.0.1:9300}, bound_addresses {[fe80::1]:9300}, {[::1]:9300}, {127.0.0.1:9300}

[2016-11-24T18:49:17,511][INFO ][o.e.c.s.ClusterService   ] [aDGu2B9] new_master {aDGu2B9}{aDGu2B9mQ8KkWCe3fnqeMw}{_y9RzyKGSvqYAFcv99HBXg}{127.0.0.1}{127.0.0.1:9300}, reason: zen-disco-elected-as-master ([0] nodes joined)

[2016-11-24T18:49:17,584][INFO ][o.e.g.GatewayService     ] [aDGu2B9] recovered [0] indices into cluster_state

[2016-11-24T18:49:17,588][INFO ][o.e.h.HttpServer         ] [aDGu2B9] publish_address {127.0.0.1:9200}, bound_addresses {[fe80::1]:9200}, {[::1]:9200}, {127.0.0.1:9200}

[2016-11-24T18:49:17,588][INFO ][o.e.n.Node               ] [aDGu2B9] started


한글형태소분석 실행)

$ curl -X POST -H "Cache-Control: no-cache" -H "Postman-Token: 6d392d83-5816-71ad-556b-5cd6f92af634" -d '{

  "analyzer" : "arirang_analyzer",

  "text" : "[한국] 엘라스틱서치 사용자 그룹의 HENRY 입니다."

}' "http://localhost:9200/_analyze"


형태소분석 결과)

{

  "tokens": [

    {

      "token": "[",

      "start_offset": 0,

      "end_offset": 1,

      "type": "symbol",

      "position": 0

    },

    {

      "token": "한국",

      "start_offset": 1,

      "end_offset": 3,

      "type": "korean",

      "position": 1

    },

    {

      "token": "]",

      "start_offset": 3,

      "end_offset": 4,

      "type": "symbol",

      "position": 2

    },

    {

      "token": "엘라스틱서치",

      "start_offset": 5,

      "end_offset": 11,

      "type": "korean",

      "position": 3

    },

    {

      "token": "엘라",

      "start_offset": 5,

      "end_offset": 7,

      "type": "korean",

      "position": 3

    },

    {

      "token": "스틱",

      "start_offset": 7,

      "end_offset": 9,

      "type": "korean",

      "position": 4

    },

    {

      "token": "서치",

      "start_offset": 9,

      "end_offset": 11,

      "type": "korean",

      "position": 5

    },

    {

      "token": "사용자",

      "start_offset": 12,

      "end_offset": 15,

      "type": "korean",

      "position": 6

    },

    {

      "token": "그룹",

      "start_offset": 16,

      "end_offset": 18,

      "type": "korean",

      "position": 7

    },

    {

      "token": "henry",

      "start_offset": 20,

      "end_offset": 25,

      "type": "word",

      "position": 8

    },

    {

      "token": "입니다",

      "start_offset": 26,

      "end_offset": 29,

      "type": "korean",

      "position": 9

    }

  ]

}


:

[Elasticsearch] Elasticsearch에 Arirang 외부 사전 등록하기

Elastic/Elasticsearch 2016. 3. 17. 12:49

arirang 한글 형태소 분석기를 적용하고 사전 데이터를 업데이트 할 일들이 많이 생깁니다.

jar 안에 들어 있는 사전 데이터는 패키지 빌드 후 재배포하고 클러스터 재시작까지 해줘야 하는데요.

이런 과정 없이 사전 데이터만 외부에서 파일로 업데이트 및 관리하고 재시작 없이 바로 적용했으면 합니다.


기본적으로 이전 글에서 사전 데이터를 reload 하는 REST API를 구현해 두었습니다.

이 기능으로 일단 기능 구현은 완료가 된 것입니다.


이전 글 보기)


그럼 elasticsearch에서 어디에 사전 파일을 두고 관리를 해야 적용이 가능 할까요?

이전 글을 보시면 기본적으로 수명님이 만드신 arirang.morph 에서 classpath 내  org/apache/lucene/analysis/ko/dic 과 같이 생성 및 배치 시키시면 먼저 이 파일을 읽어 들이게 되어 있습니다.


이전 글 보기)


단, elasticsearch 실행 시 classpath 정보에 생성한 경로를 추가하지 않으시면 사전 파일들을 찾을 수 없으니 이점 유의 하시기 바랍니다.


elasticsearch classpath 설정)

elasticsearch에서 가이드 하는 것은 수정하지 마라 입니다. 하지만 수정 없이는 이를 활용할 수 없으니 이런건 수정해줘야 합니다.


$ vi bin/elasticsearch.in.sh

.....

ES_CLASSPATH="$ES_HOME/lib/elasticsearch-2.2.0.jar:$ES_HOME/lib/*:$ES_HOME/설정하신경로입력"

.....


이렇게 수정하신 후 재시작 하시고 직접 사전 정보 업데이트 후 reload api 를 이용해서 적용되는지 확인해 보시면 되겠습니다.


참고 정보 - 간단 요약)

arirang.morph 에서 properties 파일과 dic 파일 loading flow


Step 1)

load external korean.properties into classpath.

dic files are same.


Step 2)

if not exist, load korean.properties into jar.

dic files are same.


사전 데이터는 어떻게 등록 할 수 있는지 궁금하신 분은 이전 글 참고하세요.


사전 데이터 등록 예제)

:

[arirang] 사전 데이터 등록 예제

ITWeb/검색일반 2015. 11. 20. 15:15

arirang analyzer 를 사용하면서 사전 활용을 위해서는 사전 파일이 어떻게 구성이 되어 있고 관리가 되어야 하는지 알아야 합니다.

아래 공식 카페에 들어가시면 많은 정보들이 있으니 참고 하시면 되겠습니다.


[공식카페]


[형태소분석 사전 구성 및 사용법]


[사전 등록 예시]

# 위 구성 및 사용법 에서와 같이 인덱스 순서가 이렇게 되어 있습니다.

명사 동사 기타품사 하여(다)동사 되어(다)동사 '내'가붙을수있는명사 na na na 불규칙변형


# 엘사는 명사이고 동사, 기타품사, 불규칙이 아니다, 라고 가정하면 아래와 같이 표현이 됩니다.

엘사,100000000X


# 노래는 명사이고 하여 동사가 됩니다.

노래,100100000X


# 소리는 명사이고 소리내다와 같이 내가 붙을 수 있는 명사 입니다.

소리,100001000X


[사전작업 후 리로딩]

arirang-morph 패키지에서 DictionaryUtil.java 내 loadDictionary() 호출을 통해 다시 올려 줍니다.

▶ 별도 구현이 필요합니다.


[불규칙변형 태그]

원문) http://cafe.naver.com/korlucene/135

# 위에서 제일 마지막에 'X' 라는 문자가 있습니다. 이 부분에 대한 설명 입니다.

B : ㅂ 불규칙

H : ㅎ 불규칙

L : 르 불규칙

U : ㄹ 불규칙

S : ㅅ 불규칙

D : ㄷ 불규칙

R : 러 불규칙

X : 규칙


:

[Elasticsearch] arirang analyzer offset 추출 오류.

Elastic/Elasticsearch 2015. 11. 10. 15:38

[아래 문제 회피]

기본적으로 pairmap 관련 기능을 사용하지 않으면 문제를 회피 할 수 있습니다.

더 근본적으로는 관련 기능에 대한 개선이 필요 하겠지만 일단 빠르게 해결 하기 위해서 코드를 제거해 보겠습니다.


대상파일)

KoreanTokenizer.java


삭제 대상코드) 

            if(pairstack.size()>0 && pairstack.get(0)==c) {

                pairstack.remove(0);

                continue;

            }


            int closechar = getPairChar(c);

            if(closechar!=0) {

                if((pairstack.size()==0 || pairstack.get(0)!=closechar) && length>0) {

                    pairstack.add(0,closechar);

                    break;

                } else {

                    pairstack.add(0,closechar);

                    continue;

                }

            }

위 코드를 주석 처리 후 빌드해서 배포 하시면 됩니다.


+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


최근에 arirang analyzer plugin을 만들어서 elasticsearch에서 사용하고 있습니다.

사용하다 발견된 버그 공유 합니다.


[색인원본문서]

(‘14.8월)의 일환으로 ’15.3.3 상반기중(행복서울대학교 등 활용)


[Arirang Analyzed]

{

    "tokens": [

        {

            "token": "14",

            "start_offset": 2,

            "end_offset": 4,

            "type": "word",

            "position": 0

        },

        {

            "token": "8월",

            "start_offset": 5,

            "end_offset": 7,

            "type": "korean",

            "position": 1

        },

        {

            "token": "의",

            "start_offset": 8,

            "end_offset": 9,

            "type": "korean",

            "position": 2

        },

        {

            "token": "일환",

            "start_offset": 10,

            "end_offset": 12,

            "type": "korean",

            "position": 3

        },

        {

            "token": "15",

            "start_offset": 16,

            "end_offset": 18,

            "type": "word",

            "position": 4

        },

        {

            "token": "3",

            "start_offset": 19,

            "end_offset": 20,

            "type": "word",

            "position": 5

        },

        {

            "token": "3",

            "start_offset": 21,

            "end_offset": 22,

            "type": "word",

            "position": 6

        },

        {

            "token": "상반기중행복서울대학교",

            "start_offset": 23,

            "end_offset": 34,

            "type": "korean",

            "position": 7

        },

        {

            "token": "상반",

            "start_offset": 23,

            "end_offset": 25,

            "type": "korean",

            "position": 7

        },

        {

            "token": "기중",

            "start_offset": 25,

            "end_offset": 27,

            "type": "korean",

            "position": 8

        },

        {

            "token": "행복",

            "start_offset": 27,

            "end_offset": 29,

            "type": "korean",

            "position": 9

        },

        {

            "token": "서울",

            "start_offset": 29,

            "end_offset": 31,

            "type": "korean",

            "position": 10

        },

        {

            "token": "대학교",

            "start_offset": 31,

            "end_offset": 34,

            "type": "korean",

            "position": 11

        },

        {

            "token": "등",

            "start_offset": 36,

            "end_offset": 37,

            "type": "korean",

            "position": 12

        },

        {

            "token": "활용",

            "start_offset": 38,

            "end_offset": 40,

            "type": "korean",

            "position": 13

        }

    ]

}


여기서 보시면 "행복"에서 부터 offset 정보가 하나씩 줄어든것을 확인 할 수 있습니다.


[원본 변경을 통한 문제해결 - 하나]

(‘14.8월)의 일환으로 15.3.3 상반기중(행복서울대학교 등 활용)

- ’15 (apostrophe) 제거


[원본 변경을 통한 문제해결 - 둘]

(‘14.8월)의 일환으로 ’15.3.3 상반기중(행복서울대학교 등 활용)

- 8월’ (apostrophe) 추가


[원본 변경을 통한 문제해결 - 셋]

(14.8월)의 일환으로 ’15.3.3 상반기중(행복서울대학교 등 활용)

- ’14 (apostrophe) 제거


[원본 변경을 통한 문제해결 - 넷]

‘14.8월)의 일환으로 ’15.3.3 상반기중(행복서울대학교 등 활용)

- ( 제거


[해결 방법?]

- 복합 pairmap 구성에 대한 arirang analyzer 오류 수정 (tokenizer 와 filter 쪽 수정이 필요해 보입니다.)

- 원본에 대한 character normalization 작업을 통해 filter 를 합니다.

: