1. 환경 : java, elasticsearch-1.4.6, maven
analyzer 의 구성에는 루씬에서 작동을 따르므로, filter, analyzer, tokenizer 를 각 구현해줘야한다.
밑에 클래스가 index setting 에 적용되어 filter, analyzer, tokenizer를 플러그인에 바인딩한다.
그리고 해당되는 클래스 네임으로 각각 구현해주면 된다.
public class TestAnalysisBinderProcessor extends AnalysisModule.AnalysisBinderProcessor { @Overrid public void processAnalyzers(AnalyzersBindings analyzersBindings) { analyzersBindings.processAnalyzer("test_analyzer", TestAnalyzerProvider.class); } @Override public void processTokenizers(TokenizersBindings tokenizersBindings) { tokenizersBindings.processTokenizer("test_tokenizer", TestTokenizerFactory.class); } @Override public void processTokenFilters(TokenFiltersBindings tokenFiltersBindings) { tokenFiltersBindings.processTokenFilter("test_filter", TestTokenFilterFactory.class); } }TestAnalyzerProvider 클래스 구현. AbstractIndexAnalyzerProvider를 상속하고 메인 analyzer클래스를 선언한다.
public class TestAnalyzerProvider extends AbstractIndexAnalyzerProviderfilterfactory 클래스를 만들어 custom filter를 선언한다.{ private final TestAnalyzer analyzer; @Inject public TestAnalyzerProvider(Index index, @IndexSettings Settings indexSettings, Environment env, @Assisted String name, @Assisted Settings settings) throws IOException { super(index, indexSettings, name, settings); analyzer = new TestAnalyzer(version); @Override public TestAnalyzer get() { return this.analyzer; } }
public class TestFilterFactory extends AbstractTokenFilterFactory { @Inject public TestFilterFactory(Index index, @IndexSettings Settings indexSettings, @Assisted String name, @Assisted Settings settings) { super(index, indexSettings, name, settings); } @Override public TokenStream create(TokenStream tokenStream) { return new TestFilter(tokenStream); } }custom_tokenizer를 선언하는 클래스를 만든다. 잠깐 설명하자면 루씬에서 tokenizer로 분리되어 나오는 것은 TestTokenizer에 incrementToken() 을 오버라이드 구현해서 token을 만들어 그 후 지정된 filter들이 또 다시 increamentToken 함수과정 돌면서 해당 filter 로직에 의해서 tokenstream 을 만들어 낸다.
public class TestTokenizerFactory extends AbstractTokenizerFactory { @Inject public TestTokenizerFactory(Index index, @IndexSettings Settings indexSettings, @Assisted String name, @Assisted Settings settings) { super(index, indexSettings, name, settings); } @Override public Tokenizer create(Reader reader) { return new TestTokenizer(reader); } }실제 메인으로 엘라스틱 바인딩프로세스에서 호출될 Analyzer 클래스를 만들어준다. TokenStreamComponents 메소드를 구현하여 토크나이져, 필터를 적용시켜 tokenStream을 만들게 된다.
기타 불용어처리를 하기 위해 이 경우 stopwordanalzyer를 기본으로 만든다.
그리고 아래에 사용되는 TestTokenizer, TestFilter 는 따로 구현을 해주어야 한다. 그것은 lucene analyzer구현과 같다.
그 lucene analyzer를 elasticsearch에 바인딩 시키는 것이다.
흐름 :
analyzer가 사용할 filter, tokenizer를 선언한다. 필터는 여러개가 들어갈 수 있다.(tokenStream의 데코레이터 패턴으로 보면된다.)
analyzer로 reader 타입으로 들어오게 되는데 이후 filter class들로 tokensteam형태로 들어가게 되고, 해당 tokenStream을 적절히(원하는 형태로) 처리한다.
public class TestAnalyzer extends StopwordAnalyzerBase { private Version matchVersion; public TestAnalyzer(Version version) throws IOException { // stopword(불용어)를 줄 수 있다. 아래 resource에 파일로 보관했기 때문에 아래와 같이 넣어 준다. super(version, loadStopwordSet(false, TestAnalyzer.class, "stopwords.txt", "#")); this.matchVersion = version; } @Override protected TokenStreamComponents createComponents(String fieldName, Reader reader) { final Tokenizer source = new TestTokenizer(reader); TokenStream tok = new LowerCaseFilter(matchVersion, source); tok = new TestFilter(tok); tok = new StopFilter(matchVersion, tok, stopwords); return new TokenStreamComponents(source, tok); } }아래는 TestFilter 이다. tokenizer에서 분리되어진 단어들이 분리된 정보(position, type, offset)와 함께 들어가게 된다. 루씬의 TokenFilter클래스를 상속받아
increamentToken 메소드를 재정의 하면 된다.
increamentToken() 메소드를 돌면서 tokenizer로부터 만들어진 토큰들을 받아 처리한다. 즉 필터는 각 토큰들의 상태(offset, position, type)을 다시 만들어줄 수 있다.
public class TestFilter extends TokenFilter { private TypeAttribute typeAtt = addAttribute(TypeAttribute.class); // 타입을 나타냄 private CharTermAttribute termAtt = addAttribute(CharTermAttribute.class); // 토큰의 텍스트 자체를 나타냄 private OffsetAttribute offsetAtt = addAttribute(OffsetAttribute.class); // 하이라이팅될 때 그 문자의 offset을 가리킴. es의 highlight쿼리하게 될 때 중요. private PositionIncrementAttribute posIncrAtt = addAttribute(PositionIncrementAttribute.class); 문자의 거리. token의 index라고 보면됨 public TestFilter(TokenStream input) { super(input); } @Override public boolean incrementToken() throws IOException { while(input.incrementToken()) { termAtt.buffer(); 토큰 텍스트를 set해줌. offsetAtt.setOffset(텍스트 시작위치, 텍스트 끝 위치 ); typeAtt.setType( 토큰 타입 ); posIncrAtt.setPositionIncrement(토큰 순서); } } }
이클래스에서 위에서 만든 analyzer, filter, tokenizer들을 elasticesearch로 바인딩한다.
public class TestAnalyzerPlugin extends AbstractPlugin { @Override public String name() { return "test-analyzer"; } @Override public String description() { return "test analyzer support"; } public void onModule(AnalysisModule module) { module.addProcessor(new TestAnalysisBinderProcessor()); } }
적용 방법 :
main/resource/es-plugin.properties 파일을 생성 후 plugin=org.elastic.com.TestAnalyzerPlugin
입력 후 저장
이것은 ES에서 따로 설치 과정을 거치지 않고 지정된 디렉토리에서 바로 플러그인을 인식하도록 한다.
mvn package 하여 패키징한다.
elastic plugins 디렉토리 밑에 name 함수에 선언한 "test-analyze" 라는 이름으로 디렉토리를 만들고
밑에 위 소스들을 패키징한 jar를 위치시킨다
인덱스 만들시에 setting 에 아래와 같이 추가해서 인덱스를 만들어준다.
{ "analysis":{ "analyzer":{ "test_analyzer":{ "type":"org.elastic.com.TestAnalyzerPlugin", "tokenizer":"test_tokenizer", "filter":["trim","test_filter","lowercase"] } } }
자바의 경우
XContentBuilder indexSettings = XContentFactory.jsonBuilder(); indexSettings.startObject() .startObject("analysis") .startObject("analyzer") .startObject("test_analyzer") .field("type","com.elastic.plugin.TestAnalyzerProvider") .field("tokenizer","test_tokenizer") .field("filter",new String[]{"lowercase","trim","test_filter"}) .endObject() .endObject() .endObject() .endObject(); CreateIndexRequestBuilder indexCreateRequest = client.admin().indices().prepareCreate("test_index_v1) .setSettings(indexSettings); indexCreateRequest.execute().actionGet();
정리를 하자면 input -> tokenizer -> tokenfilter -> tokenfilter -> tokenfilter (다수 토큰필터를 적용가능, 물론 코드상 처리순서대로 데이터에 적용됨.)
위의 흐름은 각 사이에 모두 tokenStream 형태로 교환되어 increamentToken()을 통해 문장에서 떨어진 각 단어?토큰 들에 접근이 가능하게 된다. 이런 것들을 이용하여 자체적인 비즈니스 로직이 더해진 색인어를 만들 수 있다.
예를 들면 "게임중에 음료수를 마신다." 를 whitespaceAnalyze 한 다음 형태소 분석을 통해 "게임중에"의 조사를 때고 "게임"으로 바꾼 다던지, 색인이 필요없는 것들은 불용어 처리를 하고,
용언등에 대한 처리를 더하는 등을 할 수 있다.
'프로그래밍 > ElasticSearch' 카테고리의 다른 글
[Elasticsearch] score 결과 보기 (explain) (0) | 2015.06.13 |
---|---|
[Elasticsearch] elasticsearch analyze결과 보기 (0) | 2015.06.13 |
[Elasticsearch] 샤드, 레플리카 갯수 설정 (0) | 2015.05.28 |
Elasticsearch cluster health check (0) | 2015.05.15 |
elasticsearch query, filter 사용 차이 (0) | 2015.05.07 |