본문 바로가기

Lucene

[루씬] 동의어 필터

제가 만들어서 사용하던 Analyzer에서 쓰던
동의어 필터입니다.

쇼핑몰을 염두해두고 작업했던 분석기라서 동의어 처리가 필요했는데요
아이디어 및 기초 소스는 루씬인액션 책에서 얻었고..
그 소스를 좀 수정해서 만들었습니다.

책에는 영어의 동의어를 어디 사이트에서 가져올 수 있다고 되어 있었는데
한글은 그런 사이트를 찾을 수가 없어서 생각해보다가
Analyzer의 최초 인스턴스 생성시 RamDirectory를 사용해서 동의어를 색인해 놓고
Token에 대한 동의어를 뽑아주는 방식을 사용했습니다.

동의어사전의 형식은 그냥

오라클,oracle
노트북,notebook,note피씨
식으로 한 row에 ,로 구분해서 넣어주시면 되고
사전명은 디폴트로 synonym.txt로 설정되어 있습니다.

위치는 webapplication이시라면 classes 밑에 사전을 넣어주시면 됩니다.
(소스 수정하셔서 원하시는 위치에 넣어주셔도 될 것 같습니다.)

루씬에서 기본적으로 제공되는 다른 필터와 마찬가지로
TokenFilter를 사용해서 만들었고, public Token next(final Token reusableToken) 메서드를 구현했습니다.

필요하신분 계시면 한번 사용해보세요..~

log를 찍기위한 commons-logging.jar가 필요합니다..


메일로 어느분께서 사용 방법을 문의를 하셔서...
보내드렸던 답변을 여기도 같이 올립니다.

일단 동의어필터에서 별다른 소스 수정은 필요하지 않고
동의어 사전이 필요합니다.

동의어 사전을 읽어오는 방식이
InputStream inputStream = getClass().getClassLoader().getResourceAsStream(SYONYM_DICTIONARY_NAME);
이고, WEB-INF/classes 에 동의어 사전을 넣으시면 됩니다. (synonym.txt)
동의어 사전의 형식은
라인 단위로

노트북,notebook
오라클,oracle,DB
에어컨,에어콘,aircon

이런식으로 작성하시면 됩니다.


그리고, 사용하시는 루씬 Analyzer에 동의어 필터를 사용하도록 하여야 하는데
Analyzer를 열어보시면

public TokenStream tokenStream(String fieldName, Reader reader) 혹은
public TokenStream reusableTokenStream(String fieldName, Reader reader) throws IOException { }

이런 메서드가 있고 두 메서드 중 하나를 사용해서
색인을 하고 있을 겁니다.

여기에 해당 Token을 사용하도록 수정을 해주시면 됩니다.

제가 사용하는 Analyzer 같은 경우는

    public TokenStream tokenStream(String fieldName, Reader reader) {
        return     new KoreanSynonymFilter(
                    new KoreanCompoundsNounExtractFilter(
                            new KoreanTokenizer(reader),this.type
                    )
                );
    }



    public TokenStream reusableTokenStream(String fieldName, Reader reader) throws IOException {
        SavedStreams streams = (SavedStreams) getPreviousTokenStream();
        if(streams == null) {
            if(logger.isDebugEnabled())
                logger.debug("새로운 토큰 스트림 생성");
            streams = new SavedStreams();
            streams.tokenStream = new KoreanTokenizer(reader);
            streams.filteredTokenStream = new LowerCaseFilter(streams.tokenStream);
            streams.filteredTokenStream = new KoreanCompoundsNounExtractFilter(streams.filteredTokenStream, this.type);
            streams.filteredTokenStream = new KoreanSynonymFilter(streams.filteredTokenStream);
            streams.filteredTokenStream = new KoreanStopFilter(streams.filteredTokenStream);
        } else {
            if(logger.isDebugEnabled())
                logger.debug("use 이전 SavedStream");
            streams.tokenStream.reset(reader);
        }

        streams.tokenStream.setMaxTokenLength(maxTokenLength);

        streams.tokenStream.setReplaceInvalidAcronym(replaceInvalidAcronym);

        return streams.filteredTokenStream;
    }

이렇게 되어 있습니다.

위 Analyzer는 제가 개발해서 쓰고 있는 Analyzer여서
가지고 계신 Analyzer와는 Filter가 차이가 있을 수 있습니다.

주의하실 점은 동의어 필터는 색인어를 추출하는 Filter 뒤에 위치해야 합니다.

그래야 추출된 키워드를 가지고 동의어 사전을 찾아서
동의어를 색인 할 수 있습니다.


동의어필터는 Analyzer가 최초 구동시
동의어 사전을 읽어 메모리에 색인을 해 놓고
추출된 키워드를 가지고, 색인된 동의어 사전을 search하여
동의어 리스트를 추출하는 방식을 사용하고 있습니다.