2015년 8월 31일 월요일

Mac에서 MeCab Ko의 Java API 사용하기


Mac에서 Mecab Ko를 수정한 후 디버깅 환경을 구축할 때 생각보다 삽질을 많이 해서 글을 남긴다.

Mac에서 MeCab Ko의 Java API 구축 환경


MacBook Pro (Retina, 15-inch, Late 2013)
Mac OS X 10.10.5
2.3 GHz Intel Core i7
16GB 1600 MHz DDR3

GCC 컴파일러 설치 여부 확인


$gcc -v

configure: error: C compiler cannot create executables
Mac OS에서 위와 같은 메시지가 출력하면 컴파일러가 설치되지 않은 것이다.

App Store > Xcode 설치

mecab-ko 설치

    mecab-0.996-ko-0.9.2.tar.gz 다운로드

2. 압축풀기 및 컴파일
    $ tar xvfz mecab-0.996-ko-0.9.2.tar.gz
    $ cd mecab-0.996-ko-0.9.2
    $ ./configure
    $ make
    $ make check
    $ make install



mecab-ko-dic 설치

    mecab-ko-dic-2.0.1-20150825.tar.gz 다운로드

2. 압축풀기 및 컴파일
    $ tar xvfz mecab-ko-dic-2.0.1-20150825.tar.gz
    $ cd mecab-ko-dic-2.0.1-20150825
    $ ./configure
    $ sudo ./autogen.sh
    $ make
    $ make install

    # autogen.sh의 실행을 안하면 Mac에서는 make에서 AM_INIT_AUTOMAKE(mecab-ko-dic, 2.0.0)라는 컴파일 에러가 발생한다.


mecab-ko-lucene-analyzer 설치

    mecab-java-0.996.tar.gz 다운로드

2. 압축풀기 및 컴파일
    $ tar xvfz mecab-java-0.996.tar.gz
    $ cd mecab-java-0.996
     > ! Mac에서는 Makefile이 제대로 동작하지 않기 때문에 다음과 같이 변경한다.
     > 빨간색으로 표시한 영역이 수정된 설정값이다.
    $ vi Makefile

TARGET=MeCab
JAVAC=javac
JAVA=java
JAR=jar
CXX=c++
INCLUDE=/System/Library/Frameworks/JavaVM.framework/Versions/A/Headers

PACKAGE=org/chasen/mecab

LIBS=`mecab-config --libs`
INC=`mecab-config --cflags` -I$(INCLUDE) -I$(INCLUDE)/MacOS

all:
        $(CXX) -O3 -c -fpic $(TARGET)_wrap.cxx  $(INC)
        $(CXX) -dynamiclib  $(TARGET)_wrap.o -o lib$(TARGET).dylib $(LIBS)
        $(JAVAC) $(PACKAGE)/*.java
        $(JAVAC) test.java
        $(JAR) cfv $(TARGET).jar $(PACKAGE)/*.class

test:
        env DYLD_LIBRARY_PATH=. $(JAVA) test

clean:
        rm -fr *.jar *.o *.dylib *.so *.class $(PACKAGE)/*.class

cleanall:
        rm -fr $(TARGET).java *.cxx


          > 수정이 다 되었으면 저장

      >> make 명령을 실행해서 libMeCab.dylib와 MeCab.jar가 생성되어 있어야 한다.
     
      $ make

      컴파일이 성공적으로 완료되면 디렉토리명을 수정한후 경로를 다음과 같이 변경하자.
      mv mecab-java-0.996 mecab-java    # 디렉토리 이름을 변경
      mv mecab-java /usr/local/bin/           # 디렉토리 위치 변경

      로컬 계정의 profile파일에 동적 라이브러리 경로를 추가하자
      $ cd ~/
      $ vi .bash_profile

      export DYLD_LIBRARY_PATH=/usr/local/bin/mecab-java

      # 저장 후 반영
      $ . .bash_profile


MeCab에서 형태소 분석 프로그램 작성

mecab-java-0.996 압축을 해제한 폴더에서 MeCabTest.java 파일을 만든다.

import org.chasen.mecab.Tagger;
import org.chasen.mecab.Node;
import java.util.HashMap;
import java.util.Map;
import java.util.Iterator;

public class MeCabTest {
    static {
        try {
            System.loadLibrary ( "MeCab"); // MeCab을로드
        } catch (UnsatisfiedLinkError e) {
            // MeCab을로드 할 때의 처리
            System.err.println ( "Can not load the example native code \ nMake sure your LD_LIBRARY_PATH contains \ n"+ e);
            System.exit (1);
        }
    }

    public static void main (String [] args)
    {
        HashMap map = new HashMap ();

        Tagger tagger = new Tagger (); // 형태소 분석의 준비
        String aString = "자연어처리의 시작이라 할 수 있는 형태소 분석에 대해서 알아본다.";
        System.out.println ( "입력 :"+ aString);

        tagger.parse (aString); // 이것을 쓰고 두지 않으면 다음 잘 작동하지 않았다.

           Node node = tagger.parseToNode (aString); // 노드에 분해
        for (; node! = null; node = node.getNext ()) // 노드를 순차적으로 출력
        {
            String str = node.getFeature (); // 품사 등의 정보를 저장
            String [] strAry = str.split ( ""); // ","로 구분하여 배열에 저장

            String word = node.getSurface (); // 단어를 저장
            String feature = strAry [0]; // 품사를 저장

            System.out.println (word + "\ t"+ feature); // 단어와 품사를 출력

            if (map.containsKey (word)) {
                // 만약 이미 map에 등록되어있는 단어라면 카운트 플러스
                map.put (word, map.get (word) + 1); // 단어 word로 이미 저장되어있는 카운트 수에 1을 더해 등록하기
            } else {
                // 만약 아직 map에 등록되지 않은 단어라면 카운트를 1로 등록
                map.put (word, 1); // 단어 word와 횟수는 1 세트에 저장
            }
        }

        // map에서 저장되는 단어와 개수를 출력하는
        for (Iterator it = map.entrySet (). iterator (); it.hasNext ();) {
            Map.Entry entry = (Map.Entry) it.next ();
            Object key = entry.getKey ();
            Object value = entry.getValue ();
            System.out.println ( "단어 :"+ key + "\ t 출현 횟수 :"+ value);
        }
    }
}


출력결과

javac -cp MeCab.jar MeCabTest.java
java -Djava.library.path=/usr/local/bin/mecab-java -cp .:MeCab.jar MeCabTest


입력 :자연어처리의 시작이라 할 수 있는 형태소 분석에 대해서 알아본다.
B
자연어 N
처리 N
J
시작 N
V
E
V
N
V
E
형태소 N
분석 N
J
대해서 V
알아본다 V
. S
B
단어 : 출현 횟수 :2
단어 :할 출현 횟수 :1
단어 :있 출현 횟수 :1
단어 :처리 출현 횟수 :1
단어 :시작 출현 횟수 :1
단어 :분석 출현 횟수 :1
단어 :. 출현 횟수 :1
단어 :알아본다 출현 횟수 :1
단어 :에 출현 횟수 :1
단어 :자연어 출현 횟수 :1
단어 :대해서 출현 횟수 :1
단어 :이 출현 횟수 :1
단어 :는 출현 횟수 :1
단어 :의 출현 횟수 :1
단어 :수 출현 횟수 :1
단어 :형태소 출현 횟수 :1
단어 :라 출현 횟수 :1


2015년 8월 28일 금요일

Elasticsearch를 사용하여 게시판의 첨부파일 내용 검색하기

이번에는 홈페이지 또는 기업에서 많이 사용되는 게시판의 제목과 본문 그리고 첨부된 문서의 텍스트를 검색하는 단계를 정리한다.


  • Elasticsearch 버전 1.7.1
  • Elastic search mapper attachment 버전 2.7.0

1. 필요한 플러그인 설치

Mapper Attachments Type for Elasticsearch

pdf 또는 ms-office 문서에서 텍스트 추출을 하기 위한 플러그인
문서파일은 아파치 Tika가 동작해서 attachment 유형을 사용할 수있게 해준다.

bin/plugin -install elasticsearch/elasticsearch-mapper-attachments/2.7.0

설치확인
curl  -XGET  http://localhost:9200/_nodes?pretty

2. 인덱스 매핑 정의

인덱스 매핑은 한국어 형태소분석을 사용하도록 설정한다.
설치 참고) Elasticsearch에 한국어 형태소분석기 Mecab ko 적용

PUT /test
{
"settings" : {
    "index":{
      "analysis":{
        "filter" : {
            "synonym" : {
                "type" : "synonym",
                "synonyms_path" : "analysis/synonyms.txt"
            }
        },
        "analyzer":{
          "korean":{
            "filter" : [
              "standard",
              "lowercase",
              "stop",
              "synonym"
            ],
            "type":"custom",
            "tokenizer":"mecab_ko_standard_tokenizer"
          }
        },
        "tokenizer": {
          "mecab_ko_standard_tokenizer": {
            "type": "mecab_ko_standard_tokenizer",
            "mecab_args": "-d /home/elasticsearch/knowledge/mecab/dic/mecab-ko-dic"
          }
        }
      }
    }
 },
"mappings": {
    "board" : {
      "properties": {
        "title": {
          "type": "string",
          "analyzer": "korean"
        },
        "content": {
          "type": "string",
          "analyzer": "korean"
        },
          "file": {
          "type": "attachment",
          "fields" : { "file" : { "term_vector":"with_positions_offsets", "store":"yes” } },
          "analyzer": "korean"
        }
      }
    }
  }
}

3. JDBC River를 사용해서 DB데이터 id, title, content, filePath, filterYn, createDate를 색인

JDBC River 사용하기

수동 입력의 예)
POST /test/board/1
{
 "id": "1",
 "title" : “「2015~2016년 해외 한국자료실 설치 지원 사업」수요조사 신청 안내",
 "content" : "대한민국 국립중앙도서관에서는 「2015~2016 해외 한국자료실 설치 지원 사업 : Window On Korea(WOK)」을 위한 수요조사를 실시하오니, 관심 있는 기관들의 많은 참여 바랍니다. 한국자료실 설치를 희망하는 기관은 “수요조사 신청서“를 작성하여, e-mail 또는 fax로 제출하여 주시기 바랍니다. ㅇ 2015년도 설치사업 : 2015년 5월 15일(금)까지  ㅇ 2016년도 설치사업 : 2015년 10월 30일(금)까지",
 "filePath": "/data1/attach/doc/1.docx",
 "file": "",
 "filterYn": "N",
 "createDate": "2015-08-28T12:00:00"
}

4. 첨부파일이 저장되어 있는 서버에서 Elasticsearch로 첨부파일 색인 요청을 한다.


문서파일 업데이트 데몬을 통해 해당 Index의 문서중에 filterYn값이 N인 파일을 BASE64인코딩해서 업데이트한다.

문서파일 색인 업데이트 프로세스

4.1 filterYn에서 N인 조건 + filePath가 empty가 아닌 문서 가져오기
검색조건
GET /test/board/_search
{
  "fields": ["id", "filePath"]
  ,"query": {
    "filtered": {
      "filter":
      {
        "bool": {
          "must": {"term": { "filterYn": “n" }},
          "must_not": {"term": {"filePath": ""}}
        }
      }
    }
  }
}

4.2 문서결과는 id와 filePath만 전달 받는다.
{
   "took": 14,
   "timed_out": false,
   "_shards": {
      "total": 5,
      "successful": 5,
      "failed": 0
   },
   "hits": {
      "total": 1,
      "max_score": 1,
      "hits": [
         {
            "_index": "test",
            "_type": "board",
            "_id": "1",
            "_score": 1,
            "fields": {
               "id": [
                  "1"
               ],
               "filePath": [
                  "/data1/attach/doc/1.docx"
               ]
            }
         }
      ]
   }
}

4.3 filePath 필드의 문서는 바이너리 데이터를 BASE64로 인코딩한다.
   - 바이너리 파일을 읽어서 BASE64로 반환하는 JAVA Class
     https://gist.github.com/utkarsh2012/1276960

4.4 Elasticsearch에 문서를 업데이트 요청한다. 데몬에서 Elasticsearch로 전달하는 URL
CURL로 업데이트할 경우의 예)
curl -XPOST  “localhost:9200/test/board/1/_update" -d '
{
   “doc” :
    {
         “id”: “1”,
         “filterYn”: “Y”,
         “file” : “ base64 encoding string …."
    }
}

5. 검색 결과 확인하기


GET /test/board/_search
{
  "fields": ["id", "title", "content"]
  ,"query": {
    "bool": {
         "must": [
           {
             "multi_match": {
               "query": “설치사업",
               "fields": [
                 "content^10",
                 "title^100",
                 "file"
                 ],
              "type": "cross_fields",
              "operator":"AND",
              "minimum_should_match": "75%"
             }
           }
         ]
       }
  },
  "highlight": {
    "fields": {"file": {"fragment_size" : 150, "number_of_fragments" : 3}}
  }
}

2015년 8월 25일 화요일

Elasticsearch에서 Mecab Ko 사전경로 변경하기

Elasticsearch Settings > Analysis > Analyzer, Tokenizer를 Mecab Ko로 설정한다.

Index analysis는 Analyzer, Tokenizer, TokenFilter로 구성된다.


1. Analysis 설정 구조
index
     analysis
            analyzer
                   standard : 
                          type : standard
                          stopwords : [stop, stop2]
                   myAnalyzer  :
                           type : standard
                           stopwords : [stop1, stop2, stop3]
                           max_token_length : 500
            tokenizer :
                   myTokenizer :
                          type : standard
                          max_token_length : 900
            filter :
                  myTokenFilter :
                         type : stop
                         stopwords : [stop1, stop2, stop3, stop4]

* max_token_length의 기본값은 255이다.

2. Mecab Ko Analysis 설정

setting에서 아래와 같이 사전경로 지정을 위해 tokenizer > mecab_args를 추가한다.

PUT /shop
{
"settings" : {
    "index":{
      "analysis":{
        "analyzer":{
          "korean":{
            "type":"custom",
            "tokenizer":"mecab_ko_standard_tokenizer"
          }
        },
        "tokenizer": {
          "mecab_ko_standard_tokenizer": {
            "type": "mecab_ko_standard_tokenizer",
            "mecab_args": "-d /home/elasticsearch/knowledge/mecab/dic/mecab-ko-dic"
          }
        }
      }
    }
 }
}

[분석 결과보기]
GET /shop/_analyze?analyzer=korean&pretty=true
{
  레노버노트북
}


[참고 URL]

Elasticsearch에서 Mecab Ko 동의어사전 적용하기

Elasticsearch Settings > Analysis > Filter 설정

Index analysis는 Analyzer, Tokenizer, TokenFilter로 구성된다.


TOKEN FILTER 종류
33개 
tokenizer로 부터 token stream을 받아서 token에 대해 lower case, add, delete 등을 처리

Synonym Token Filter
동의어를 적용하는 필터. Elasticsearch에 포함되어 있다.

# 설정 예제
PUT /shop
{
"settings" : {
    "index":{
      "analysis":{
        "filter" : {
            "synonym" : {
                "type" : "synonym",
                "synonyms_path" : "analysis/synonyms.txt"
            }
        },
        "analyzer":{
          "korean":{
            "filter" : [
              "standard",
              "lowercase",
              "stop",
              "synonym"  
            ],
            "type":"custom",
            "tokenizer":"mecab_ko_standard_tokenizer"
          }
        },
        "tokenizer": {
          "mecab_ko_standard_tokenizer": {
            "type": "mecab_ko_standard_tokenizer",
            "mecab_args": "-d /home/elasticsearch/knowledge/mecab/dic/mecab-ko-dic"
          }
        }
      }
    }
 }
}

# edit : $ES_HOME/config/analysis/synonym.txt 
노트북,labtop,notebook

# 확인 명령
$ curl -XGET ‘localhost:9200/shop/_analyze?analyzer=korean&pretty=true' -d ‘노트북'

# 노트북 labtop notebook  

Elasticsearch Analysis (by Elasticsearch Korea)

Elasticsearch에 Mecab Ko 사전경로 설정하는 방법을 설명하기 전에 Analysis 개념을 먼저 정리한다.

본 내용은 Elasticsearch Korea의 Youngsik Yun님 발표자료를 옮긴 것입니다.
(* 원문: http://elasticsearch-kr.github.io/presentations/2014-04-30-analysis/#/)

1. Analysis개념


Index analysis는 Analyzer, Tokenizer, TokenFilter로 구성되면 Terms 인덱스를 만든다.

2. Analyzer 구성요소


Character Filtering: Turns the input string into a different string  (Pre-processes)
Tokenization: Divide the char-filtered string into an array of tokens
Token Filtering: Post-processes the filtered tokens into a mutated token array


3. ANALYZER 종류


default  analyzer : 8종류
or
custom analyzer 작성

3.1 DEFAULT ANALYZER

standard
simple
whitespace
stop
keyword
pattern
language
snowball

1) STANDARD ANALYZER

standard Tokenizer
+ standard TokenFilter
+ lowercase TokenFilter
+ stop TokenFilter

언제 사용? 지정 한하면 기본 적용되는 analzyer이다

2) SIMPLE ANALYZER
only lower case tokenizer 만 구성

3) WHITESPACE ANALYZER
whitespace tokenizer 만 구성

4) STOP ANALYZER
lower case tokenizer
+
stop token filter
언제 사용?  stopwords 를 등록한다

5) KEYWROD ANALYZER
not_analyzed로 마킹 (이해불가)

6) PATTENRN ANALYZER
regular expression을 통해서 텍스트 분류
lowercase + pattern + flags + stopwords 옵션

7) LANGUAGE ANALYZER
지정한 단어가 나오면 analyzing 하는 목적

8) SNOWBALL ANALYZER
standard tokenizer
+ standard filter, lowercase filter
+ stop filter, snowball filter
언제 사용? streaming 분석기

3.2 CUSTOM ANALYZER
Tokenizer
+ Token Filter (zero or more)
+ Char Filters (zero or more)


4. TOKENIZER 종류

10개
standard
edge ngram
keyword
letter
lowercase
ngram
whitespace
pattern
uax email url
path heirarchy

1) STANDARD TOKENIZER
Unicode Text Segment Algorithm
basic grammer tokenizer
max_token_length (default 255)
길이 넘으면 무시

2) EDGE NGRAM TOKENIZER
nGram 과 유사
"tokenizer" : {
    "my_edge_ngram_tokenizer" : {
        "type" : "edgeNGram",
        "min_gram" : "2",
        "max_gram" : "5",
        "token_chars": [ "letter", "digit" ]
    }
}

3) KEYWORD TOKENIZER
Keyword
buffer_size   256


4) WHITESPACE TOKENIZER
text를 whitespace 별로 나눈다

5) LETTER TOKENIZER
text에서 letter 아닌 것 제거

6) LOWERCASE TOKENIZER
letter tokenizer + lowercase tokenfilter
즉, letter가 아닌 것 제거하고 lower case 로 만듦

7) NGRAM TOKENIZER
"tokenizer" : {
    "my_ngram_tokenizer" : {
        "type" : "nGram",
        "min_gram" : "2",
        "max_gram" : "3",
        "token_chars": [ "letter", "digit" ]
    }
}

8) PATTERN TOKENIZER
regular expression 사용
pattern + flags + group 옵션

9) UAZ EMAIL URL TOKENIZER
standard tokenizer 같고 email, url 나누기
max_token_length (default 255)


10) PATH HIERARCHY TOKENIZER
path 나누기
/something/something/else
And produces tokens:

/something
/something/something
/something/something/else
옵션
delimiter (default /)
replacement (option, delimiter 나오면 대체)
buffer_size (default 1024)
reverse (default false)
skip (처음 건너뛰기, default 0)


5. TOKEN FILTER 종류


33개
tokenizer로 부터 token stream을 받아서 token에 대해 lower case, add, delete 등을 처리

1) STANDARD TOKEN FILTER
normalize token

2) ASCII FOLDING TOKEN FILTER
알파벳, 숫자, 기호를 ascii 로 변환
"index" : {
    "analysis" : {
        "analyzer" : {
            "default" : {
                "tokenizer" : "standard",
                "filter" : ["standard", "asciifolding"]
            }
        }
    }
}
이렇게 FILTER를 표현
"index" : {
    "analysis" : {
        "analyzer" : {
            "default" : {
                "tokenizer" : "standard",
                "filter" : ["standard", "my_ascii_folding"]
            }
        },
        "filter" : {
            "my_ascii_folding" : {
                "type" : "asciifolding",
                "preserve_original" : true
            }
        }
    }
}

3) LENGTH TOKEN FILTER
min~max 주어서 remove word

4) LOWERCASE TOKEN FILTER
5) UPPERCASE TOKEN FILTER
6) NGRAM TOKEN FILTER
min_gram ~ max_gram

7) EDGE NGRAM TOKEN FILTER
그외 ...


6. CHARACTER FILTER 종류


Tokenizer를 통과하기 전에 string에 대한 전처리기

3개
mapping
html strip
pattern replace

1) MAPPING CHAR FILTER

맵핑 설정한 문자로 바꾸어 준다
{
    "index" : {
        "analysis" : {
            "char_filter" : {
                "my_mapping" : {
                    "type" : "mapping",
                    "mappings" : ["ph=>f", "qu=>q"]
                }
            },
            "analyzer" : {
                "custom_with_char_filter" : {
                    "tokenizer" : "standard",
                    "char_filter" : ["my_mapping"]
                },
            }
        }
    }
}

2) HTML STRIP CHAR FILTER
html strip


3) PATTERN REPLACE CHAR FILTER
regex



7. ICU ANALYSIS PLUGIN


ICU? International Components for Unicode

종류
icu_normalization
icu_folding
filtering
icu_collation

Elasticsearch에서 failed to execute script 해결 방법

Elasticsearch의 Index API를 학습하다가 아래와 같은 에러를 만나게 된다.

{
   "error": "ElasticsearchIllegalArgumentException[failed to execute script]; nested: ScriptException[scripts of type [inline], operation [update] and lang [groovy] are disabled]; ",
   "status": 400
}

에러가 발생하는 이유는,
Elasticsearch에서 scripting 모듈은 기본적으로 groovy를 사용하고 있지만 보안 취약점으로 인하여 비활성화 되어 있기 때문이다.

해결방법으로는 elasticsearch.yml에 script.inline: on 을 추가하면 된다.

2015년 8월 24일 월요일

Google Trends, Lucene & Elasticsearch & SOLR


구글 트랜드로 Elasticsearch, SOLR, Lucene의 관심도를 비교해본다.

아래와 같이 비교 검색어를 입력했다.




예측 결과를 보면 Elasticsearch가 앞으로도 그래프가 상승곡선을 그리고 있다.
SOLR는 Lucene처럼 하락세라고 보기는 힘들지만 Hot한 시기는 지나간거 같다.

다음으로 3가지 키워드의 관심이 높은 지역을 살펴본다.
Elasticsearch는 대한민국이 1위다. 2015년도에 국내에서 Elasticsearch의 인기가 정말 높은 것 같다.


SOLR는 인도와 중국에서 인기가 높은 것을 알 수 있다. 
인도와 중국에 진출하실 분들은 검색엔진으로 SOLR를 고려해보셔야 할 것 같다.


Elasticsearch에 한국어 형태소분석기 Mecab ko 적용

최근에 Elasticsearch를 정리하면서 MeCab Ko의 Elasticsearch 연동을 정리하지 않은 것 같아서 작성 해 본다.
(사실 SOLR에 MeCab Ko를 먼저 붙였지만, 최근에 Elasticsearch만 정리하고 있다. ㅡㅡ;)

참고) SOLR와 Elasticsearch에서 MeCab을 사용할 때 특수문자 허용 검색하기
http://nocode2k.blogspot.kr/2015/08/mecab-ko-solr-elasticsearch.html

CentOS 6.x 환경에서 SOLR와  Elasticsearch에서 한국어 형태소분석기인 Mecab Ko를 사용하기 위해서는 먼저 아래와 같이 설치 및 환경설정이 필요하다.
(* 8월 20일 현재 은전한닢 프로젝트에서는 mecab ko 사전을 사용하는 스칼라로 개발된 형태소분석기도 배포중이다.)

1. GCC컴파일러/JDK설치


1.1 C++ 컴파일러 설치
yum install gcc-c++

1.2 Java 다운로드 및 설치

사이트 다운로드 : http://www.oracle.com/technetwork/java/javase/downloads/index.html

리눅스 command 다운로드

32 bit linux use this:
curl -v -j -k -L -H "Cookie: oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/8u51-b16/jdk-8u51-linux-i586.rpm > jdk-8u51-linux-i586.rpm

For 64 bit:
curl -v -j -k -L -H "Cookie: oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/8u51-b16/jdk-8u51-linux-x64.rpm > jdk-8u51-linux-x64.rpm

Install the rpm:
rpm -ivh  jdk-8u51-linux-i586.rpm


2. mecab-ko 설치


mecab-ko는 한국어 특성에 맞는 기능이 추가된 MeCab의 fork 프로젝트이다.
mecab-ko 다운로드 페이지에서 mecab-ko의 소스를 다운로드 받고 설치한다.

사이트 다운로드: https://bitbucket.org/eunjeon/mecab-ko/downloads

리눅스 command 다운로드 및 설치

wget https://bitbucket.org/eunjeon/mecab-ko/downloads/mecab-0.996-ko-0.9.2.tar.gz

tar -zxvf mecab-0.996-ko-0.9.2.tar.gz

cd mecab-0.996-ko-0.9.2

./configure --with-charset=utf-8

make

make check

make install


# /usr/local/bin 아래에 실행바이너리 파일이, /usr/local/lib 아래에 라이브러리가, 그리고 /usr/local/etc 아래에 설정 파일인 mecabrc가 설치된다.


3. mecab-ko-dic 설치


mecab-ko-dic 다운로드 페이지에서 mecab-ko-dic의 최신버전을 다운로드 받는다.

사이트 다운로드: https://bitbucket.org/eunjeon/mecab-ko-dic/downloads

리눅스 command 다운로드 및 설치

wget https://bitbucket.org/eunjeon/mecab-ko-dic/downloads/mecab-ko-dic-2.0.1-20150707.tar.gz

tar zxvf mecab-ko-dic-2.0.1-20150707.tar.gz

cd mecab-ko-dic-2.0.1-20150707

./configure --with-charset=utf-8

make

make install

# /usr/local/lib/mecab/dic/mecab-ko-dic 아래에 사전이 설치된다.

4. mecab 테스트


$ /usr/local/bin/mecab -d /usr/local/lib/mecab/dic/mecab-ko-dic
mecab-ko-dic은 MeCab을 사용하여, 한국어 형태소 분석을 하기 위한 프로젝트입니다.
mecab    SL,*,*,*,*,*,*,*
-    SY,*,*,*,*,*,*,*
ko    SL,*,*,*,*,*,*,*
-    SY,*,*,*,*,*,*,*
dic    SL,*,*,*,*,*,*,*
은    JX,*,T,은,*,*,*,*
MeCab    SL,*,*,*,*,*,*,*
을    JKO,*,T,을,*,*,*,*
사용    NNG,*,T,사용,*,*,*,*
하    XSV,*,F,하,*,*,*,*
여    EC,*,F,여,*,*,*,*
,    SC,*,*,*,*,*,*,*
한국어    NNG,*,F,한국어,Compound,*,*,한국/NNG/*+어/NNG/*
형태소    NNG,*,F,형태소,Compound,*,*,형태/NNG/*+소/NNG/*
분석    NNG,*,T,분석,*,*,*,*
을    JKO,*,T,을,*,*,*,*
하    VV,*,F,하,*,*,*,*
기    ETN,*,F,기,*,*,*,*
위한    VV+ETM,*,T,위한,Inflect,VV,ETM,위하/VV/*+ᆫ/ETM/*
프로젝트    NNG,*,F,프로젝트,*,*,*,*
입니다    VCP+EF,*,F,입니다,Inflect,VCP,EF,이/VCP/*+ᄇ니다/EF/*
.    SF,*,*,*,*,*,*,*
EOS


5. mecab-java 설치


사이트 다운로드: https://bitbucket.org/eunjeon/mecab-ko-lucene-analyzer

리눅스 command 다운로드 및 설치
wget https://bitbucket.org/eunjeon/mecab-java/downloads/mecab-java-0.996.tar.gz

tar -zxvf mecab-java-0.996.tar.gz

cd mecab-java-0.996

# Makefile 수정
vi Makefile

# Makefile 에서 INCLUDE 변수에 java include directory를 설정해준다.
INCLUDE=/usr/java/jdk1.8.0_51/include

# Makefile에서 GCC optimization 옵션을 O3에서 O1으로 변경한다.
# 은전한닢에서는 OpenJDK사용시 변경하라고 되어 있으나 Oracle JDK에서도 변경해줘야 한다.
all:
        $(CXX) -O1 -c -fpic $(TARGET)_wrap.cxx  $(INC)
        $(CXX) -shared  $(TARGET)_wrap.o -o lib$(TARGET).so $(LIBS)
        $(JAVAC) $(PACKAGE)/*.java
        $(JAVAC) test.java
        $(JAR) cfv $(TARGET).jar $(PACKAGE)/*.class

# 저장
:wq

make

cp libMeCab.so /usr/local/lib


6. 환경 설정


CentOS에서 Elasticsearch를 실행하는 계정의 환경설정파일(예: .bashrc)에 라이브러리 경로를 추가한다.

LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/local/lib"
export LD_LIBRARY_PATH

7. Elasticsearch MeCab 플러그인 설치


./bin/plugin --install analysis-mecab-ko-0.17.0 --url https://bitbucket.org/eunjeon/mecab-ko-lucene-analyzer/downloads/elasticsearch-analysis-mecab-ko-0.17.0.zip


8. Elasticsearch 재시작 및 analyzer 테스트


8.1 Elasticsearch 실행
bin/elasticsearch -Djava.library.path=/usr/local/lib


8.2 index 생성 
curl -XPUT ‘localhost:9200/INDEX_NAME’
예)
curl -XPUT ‘localhost:9200/eunjeon’

8.3 index close
curl -XPOST 'localhost:9200/eunjeon/_close’

8.3 analyzer 추가 
curl -XPUT 'localhost:9200/eunjeon/_settings’ -d ’{
   "index": {
      “analysis”: {
         "analyzer": {
               "korean": {
                       "type": “custom”,
                       "tokenizer": “mecab_ko_standard_tokenizer”
                }
          }
      }
   }
}’

테스트)
curl -XGET 'localhost:9200/eunjeon/_analyze?analyzer=korean\&pretty=true -d '은전한닢 프로젝트'

8.4 index open
curl -XPOST 'localhost:9200/eunjeon/_open’


8.5 type에 대한 _mapping 설정 추가

한글 형태소 분석기 적용된 mapping 추가의 예)

curl -XPUT 'localhost:9200/eunjeon/_mapping/survey’ -d ’{
     "properties":{  
           "title":{      
                  "type":"string",      
                  "analyzer":"korean"  
          }
    }
}’

설정값 확인)
curl -XGET 'localhost:9200/eunjeon/_settings?pretty=1’


[참고 사이트]

은전한닢 프로젝트: http://eunjeon.blogspot.kr
은전한닢 프로젝트 구글 포럼: https://groups.google.com/forum/#!forum/eunjeon

2015년 8월 17일 월요일

Elasticsearch 시작하기 (Elasticsearch Getting Started Webinar)



Elastic 제품 포트폴리오 (The Elastic Product Portfolio)



[이미지 출처: www.elastic.co]


0. Elasticsearch의 특징


  • real-time
  • distributed
  • search
  • analytics
표 1 관계형 데이터베이스와 elasticsearch 용어 비교
관계형 데이터베이스elasticsearch
DatabaseIndex
TableType
RowDocument
ColumnField
SchemaMapping
IndexEverything is indexed
SQLQuery DSL



1. Elasticsearch 설치

1.1 Java 다운로드 및 설치

1.1.1 사이트 다운로드 

1.1.2 리눅스 command 다운로드
32 bit linux use this:
curl -v -j -k -L -H "Cookie: oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/8u51-b16/jdk-8u51-linux-i586.rpm > jdk-8u51-linux-i586.rpm

For 64 bit:
curl -v -j -k -L -H "Cookie: oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/8u51-b16/jdk-8u51-linux-x64.rpm > jdk-8u51-linux-x64.rpm

Install the rpm:
rpm -ivh  jdk-8u51-linux-i586.rpm


1.2 Elasticsearch 지원 Java 버전
Product and JVM

1.3 Elasticsearch 다운로드

1.3.1 사이트 다운로드

1.3.2 리눅스 command 다운로드
curl -L -O http://download.elasticsearch.org/PATH/TO/VERSION.zip
unzip elasticsearch-$VERSION.zip
cd elasticsearch-$VERSIO


1.3.3 Elasticsearch 디렉토리 구성

$tree -L 2

.
├── LICENSE.txt
├── NOTICE.txt
├── README.textile
├── bin
│   ├── elasticsearch
│   ├── elasticsearch-service-mgr.exe
│   ├── elasticsearch-service-x64.exe
│   ├── elasticsearch-service-x86.exe
│   ├── elasticsearch.bat
│   ├── elasticsearch.in.bat
│   ├── elasticsearch.in.sh
│   ├── plugin
│   ├── plugin.bat
│   └── service.bat
├── config
│   ├── elasticsearch.yml
│   └── logging.yml
├── data
│   └── elasticsearch
├── lib
│   ├── antlr-runtime-3.5.jar
│   ├── apache-log4j-extras-1.2.17.jar
│   ├── asm-4.1.jar
│   ├── asm-commons-4.1.jar
│   ├── elasticsearch-1.6.0.jar
│   ├── groovy-all-2.4.0.jar
│   ├── jna-4.1.0.jar
│   ├── jts-1.13.jar
│   ├── log4j-1.2.17.jar
│   ├── lucene-analyzers-common-4.10.4.jar
│   ├── lucene-core-4.10.4.jar
│   ├── lucene-expressions-4.10.4.jar
│   ├── lucene-grouping-4.10.4.jar
│   ├── lucene-highlighter-4.10.4.jar
│   ├── lucene-join-4.10.4.jar
│   ├── lucene-memory-4.10.4.jar
│   ├── lucene-misc-4.10.4.jar
│   ├── lucene-queries-4.10.4.jar
│   ├── lucene-queryparser-4.10.4.jar
│   ├── lucene-sandbox-4.10.4.jar
│   ├── lucene-spatial-4.10.4.jar
│   ├── lucene-suggest-4.10.4.jar
│   ├── sigar
│   └── spatial4j-0.4.1.jar
├── logs
│   ├── elasticsearch.log
│   ├── elasticsearch_index_indexing_slowlog.log
│   └── elasticsearch_index_search_slowlog.log
└── plugins
   ├── bigdesk
   ├── head
   └── kopf


2. 기본 설정
elasticsearch.yml

1. cluster.name을 설정한다.
ex: clustre.name: elasticsearch_dev01

2. node.name을 설정한다.
ex: node.name: search_dev01

3. JVM의 스왑을 방지하려면 아래 설정 값을 true로 한다.
bootstrap.mlockall: true

4. 호스트 설정
network.host: 127.0.0.1

5. http port 설정
http.port: 9200

6. Elasticsearch 실행
~/bin/elasticsearch

curl -XGET localhost:9200/_cluster/health
curl -XGET localhost:9200/_cluster/health?pretty
{
 "cluster_name" : "elasticsearch_dev01",
 "status" : "green",
 "timed_out" : false,
 "number_of_nodes" : 1,
 "number_of_data_nodes" : 1,
 "active_primary_shards" : 0,
 "active_shards" : 0,
 "relocating_shards" : 0,
 "initializing_shards" : 0,
 "unassigned_shards" : 0,
 "number_of_pending_tasks" : 0,
 "number_of_in_flight_fetch" : 0
}


Head 플러그인 설치
./plugin -i mobz/elasticsearch-head

Marvel 플러그인 설치
./plugin -i elasticsearch/marvel/latest




3. CRUD Operations

http://localhost:9200/_plugin/marvel/sense/index.html

 

#____________________________________________________
# Document CRUD operation
#____________________________________________________

#____________________________________________________
# Index a JSON document

#      ----  Index name
#      |
#      |        ----- Type name
#      |        |
#      |        |     ---- Doc ID     
#      |        |     |
#      V        V     V
PUT /library/books/1
{
"title": "A fly on the wall",
"name": {
  "first": "Drosophila",
  "last": "Melanogaster"
},
"publish_date": "2015-07-31T12:00:00-0400",
"price": 19.95
}

#____________________________________________________
# 입력한 문서 ID 데이터 얻기
GET /library/books/1

#____________________________________________________
# DOC ID없이 저장하기
POST /library/books/
{
 "title": "Adventures of Strange-Foot Smooth",
"name": {
  "first": "Xenopus",
  "last": "laevis"
},
"publish_date": "2015-07-31T12:12:00-0400",
"price": 5.99
}

#____________________________________________________
# GET 할때는 위에서 자동 생성된 ID가 필요하다.
GET /library/books/AU7iHhAcxZSlo5TsOhLA

#____________________________________________________
# 문서 전체업데이트
PUT /library/books/1
{
"title": "A fly on the wall PART2",
"name": {
  "first": "Drosophila",
  "last": "Melanogaster"
},
"publish_date": "2015-07-31T12:00:00-0400",
"price": 29.95
}

GET /library/books/1

#____________________________________________________
# 문서 업데이트 API
POST /library/books/1/_update
{
 "doc": {
   "price" : 10
 }
}

GET /library/books/1

#____________________________________________________
# 문서 업데이트 API - 필드추가
POST /library/books/1/_update
{
 "doc": {
   "cn_price" : 13
 }
}

GET /library/books/1

#____________________________________________________
# 문서 삭제
DELETE /library/books/1

GET /library/books/1


# 참고 URL

#______________________________________________
# Bulk indexing and Search
DELETE /library/books/
#______________________________________________
# 여러 문서의 색인이 필요할때, bulk API를 사용하면 된다.

POST /library/books/_bulk
{ "index": {"_id": 1}}
{ "title": "The quick brown fox", "price": 5}
{ "index": {"_id": 2}}
{ "title": "The quick brown fox jumps over the lazy dog", "price": 15}
{ "index": {"_id": 3}}
{ "title": "The quick brown fox jumps over the quick dog", "price": 8 }
{ "index": {"_id": 4}}
{ "title": "Brown fox brown dog", "price": 2}
{ "index": {"_id": 5}}
{ "title": "Lazy dog", "price": 9}

# 참고 URL


4. Query & Search syntax

#____________________________________________________
# 기본적인 검색 수행하기
# 문서 검색 *all*

GET /library/books/_search

#____________________________________________________
# “fox”가 포함된 모든 문서 검색

GET /library/books/_search
{
 "query" : {
    "match" : {
        "title": "fox"
     }
  }
}

#____________________________________________________
# “quick” and “dog” 검색하는 방법?

GET /library/books/_search
{
 "query" : {
   "match" : {
     "title": “quick dog"
   }
 }
}

#____________________________________________________
# 문서 내의 구문검색
GET /library/books/_search
{
 "query" : {
   "match_phrase" : {
     "title": “quick dog"
   }
 }
}

# 참고 URL

#____________________________________________________
# boolean 조합검색
# 검색 형식
GET /library/books/_search
{
 "query" : {
     "bool": {
       "must": [
           {}
         ],
       “must_not” : [
          {}
        ],
       “should”: [
          {}
       ]
     }
  }
}

# “quick” and “lazy dog”이 포함된 모든 문서를 찾아보자
GET /library/books/_search
{
 "query" : {
     "bool": {
       "must": [
         {
           "match": {
             “title”:"quick"
           }
         },
         {
           "match_phrase": {
             "title": “lazy dog"
           }
         }
         ]
     }
  }
}

# 조합검색에서 다른 효과를 주기 위해서 boost를 사용한다.
# 검색결과 품질을 높일 수 있다.
GET /library/books/_search
{
 "query" : {
     "bool": {
       "should": [
           {
             "match_phrase" :{
               "title" : {
                 "query": “quick dog",
                 "boost" : 0.5
               }
             }
           },
           {
             "match_phrase": {
               "title": {
                 "query": “lazy dog"
               }
             }
          }
       ]
     }
 }
}

#____________________________________________________
# 검색 키워드 하이라이팅
GET /library/books/_search
{
 "query" : {
     "bool": {
       "should": [
           {
             "match_phrase" :{
               "title" : {
                 "query": "quick dog",
                 "boost" : 0.5
               }
             }
           },
           {
             "match_phrase": {
               "title": {
                 "query": "lazy dog"
               }
             }
          }
       ]
     }
 },
"highlight" : {
   "fields": {
     "title" : {}
   }
 }
}

#____________________________________________________
# 필터링 검색
# 필터링은 쿼리(query)보다 빠르다.

# 필터링 검색 - 가격이 5$ 이상인 모든 책을 찾기
GET /library/books/_search
{
 "query" : {
   "filtered": {
     "filter": {
       "range": {
         "price": {
           "gte": 5
         }
       }
     }
   }
 }
}

# 필터링 - 키워드와 가격이 5$ 이상인 모든 책을 찾기
GET /library/books/_search
{
 "query" : {
   "filtered": {
     "query": {
       "match": {
         "title": “lazy dog"
       }
     },
     "filter": {
       "range": {
         "price": {
           "gte": 5
         }
       }
     }
   }
 }
}

# 참고 URL


5. Analysis의 이해

# Analysis는 tokenization + token filters 이다.

#____________________________________________________
# 토크나이저와 필터링
GET /library/_analyze?tokenizer=standard
{
 “Brown fox brown dog"
}

GET /library/_analyze?tokenizer=standard&filters=lowercase
{
 “Brown fox brown dog"
}

# 토크나이저와 필터링 결과에서 유일한 결과만 얻기
GET /library/_analyze?tokenizer=letter&filters=unique,truncate
{
 “Brown brown brown fox brown dog"
}

#____________________________________________________
# A tokenize + 0  or more token filters == analyzer
GET /library/_analyze?tokenizer=standard
{
 “Brown fox brown dog"
}
#____________________________________________________
# Analysis를 이해하는 것은 매우 중요하다.
# 왜냐하면 토큰나이저는 다양하게 쓸 수 있기 때문이다.
GET /library/_analyze?tokenizer=standard&filters=lowercase,kstem
{
 "THE quick.brown_FOx Jumped! $19.95 @ 3.0"
}

GET /library/_analyze?tokenizer=letter&filters=lowercase
{
 "THE quick.brown_FOx Jumped! $19.95 @ 3.0"
}

# 참고 URL


6. Mappings overview (schema 정의)

GET /library/_mapping

#____________________________________________________
# 새로운 필드 추가
PUT /library/books/_mapping
{
 "books": {
   "properties": {
     "my_new_field": {
       "type": "string"
     }
   }
 }
}

GET /library/_mapping

#____________________________________________________
# analyzers, etc
PUT /library/books/_mapping
{
 "books": {
   "properties": {
     "english_field": {
       "type": "string",
       "analyzer": "english"
     }
   }
 }
}

GET /library/_mapping

#____________________________________________________
# 필드의 타입과 분석방식을 변경하려면 에러발생!
PUT /library/books/_mapping
{
 "books": {
   "properties": {
     "english_field": {
       "type": "long",
       "analyzer": "cjk"
     }
   }
 }
}

# 해결방법 - https://gist.github.com/nicolashery/6317643

#____________________________________________________
# long타입의 필드에 double 데이터가 저장된 경우
# 문제를 해결하는 방법

POST /logs/transactions/
{
 "id": 234571
}

POST /logs/transactions/
{
 "id": 1391.223
}

GET /logs/transactions/_search
{
 "query": {
   "filtered": {
     "filter": {
       "range": {
         "id": {
           "gt": 1391,
           "lt": 1392
         }
       }
     }
   }
 }
}

GET /logs/_mapping
GET /logs/_search

# 문제해결 참고 URL