본문 바로가기

Lucene

[Lucene] Analyzer의 reusableTokenStream

댓글로 질문을 하신분이 계셔서 그 내용을 확인하고 답변을 드리기 위해서
포스트를 작성합니다.

질문하신 내용은
Custom Analyzer를 만들어서 사용하는데
실제로 원하는대로 작동을 하지 않는다는 것이었습니다. Custom Analyzer의 로직은 아래와 같습니다.



즉, 사용자에게 입력받은 키워드를 별도로 준비된 형태소분석기를 통해서 명사를 추출하고
이 추출된 명사의 위치정보와 기타 루씬의 Filter를 적용하기 위하여 이를 다시 StandardAnalyzer로 분석하는
CustomAnalyzer였습니다.

그런데 테스트를 해보면 
처음 "무궁화 꽃이 피었습니다." 라고 실행하면 정상적으로 "무궁화" , "꽃"이 추출되어 나오는데
그 다음부터는 "무궁화", "꽃이", "피었습니다." 라고 입력된 키워드가 마치 그냥 StandardAnalyzer로 분석되는 것처럼
나온다는 것에 대한 문의 였습니다.

테스트 코드는 아래와 같습니다.


똑같은 문장 "무궁화 꽃이 피었습니다"를 3번 돌면서 분석하는 로직입니다.

보시면 Analyzer를 한번만 생성하여 loop를 돌면서 analyzer.reusableTokenStream을 사용하고 있는 것이 보입니다.

여기서 만약 Analyzer를  loop 돌때마다 new로 생성하여 사용하면 결과는 3번 모두 "무궁화", "꽃"이 분석되어 나옵니다.

문제는 reuseableTokenStream에 있는데요.. 메서드명에서 알 수 있듯이 이는 TokenStream을 재사용하는 메서드입니다.
이 메서드를 실행하게 되면 아래의 메서드가 실행됩니다.


getPreviousTokenStream에 의해서 이전에 저장된 TokenStream을 가져오고 그것이 있으면 그 Stream을 그대로 사용하도록 되어있습니다. 그 TokeStream에 사용자가 입력한 키워드를 주고 분석을 하게 되는 것 입니다.


여기서getPreviouseTokenStream에 의해서 return되는 TokenStream이 바로 CustomAnalyzer에서 만들어내고 있는
 

final Tokenizer source = new StandardTokenizer(Version.LUCENE_33, reader);

Set<String> stopSet = new TreeSet<String>();

return new TokenStreamComponents(source, new StopFilter(Version.LUCENE_33, source, stopSet)); 


이것입니다. 

즉, 첫번째 분석요청에 대해서는 형태소분석을 한 결과를 가지고 위의 TokenStream을 만들어서 적용한 결과가 정상적으로 나왔는데 그 이후의 분석 요청부터는 이미 만들어진 TokenStream이 있기 때문에 CustomAnalyzer에서 형태소분석을 요청하는 부분이 적용되지 않고 사용자가 입력한 키워드를 곧바로 위 StandardAnalyzer를 기본으로 한 TokenStream에 적용해버리기 때문입니다.

TokenStream 자체에 대한 재사용이라고 생각하시면 좋을 것 같습니다.

이를 피하는 방법은..

1. 위에서 언급된 것 처럼 new로 매번 Analyzer의 생성
2. Analyzer.reuseableTokenStream을 사용하지말고 Analyzer.tokeStream 메서드를 사용
3. TokenStream을 재사용하시려면, 실제 형태소분석을 하고 그것을 바탕으로 위치 정보를 뽑아 낼 수 있도록 
형태소분석을 전용으로 하는 Filter를 만드시는 방법

등이 있을 것 같습니다.

위와 같은 경우 "무궁화"와 "꽃"이 정상적으로 추출되는 경우라도 실제 원문과 비교하여 
위치정보등이 틀릴 수도 있습니다. 왜냐하면 위치정보를 추출한 원문이 "무궁화 꽃이 피었습니다." 가 아니라
"무궁화 꽃" 이기 때문입니다. 우연찮게 명사가 같은 위치에 있어서 결과가 제대로 나오는 것 같지만 보통의 경우에는
위치정보를 제대로 사용하실 수 없을 것입니다.

이런저런 이유로 3번이 가장 명확한 방법으로 보이네요.