레이블이 faq인 게시물을 표시합니다. 모든 게시물 표시
레이블이 faq인 게시물을 표시합니다. 모든 게시물 표시

2013년 6월 27일 목요일

Solr query를 어떻게 만드는 것이 좋을까?

편의상 평어체를 사용합니다.

Solr query parser의 문제점

Solr에 포함된 대부분의 query parser(Lucene, Dismax, ExtendedDismax 등)는 사용자의 검색어를 한번에 분석(analyze)하는 것이 아니라 여러 조각으로 나눠서 분석한다. 예를 들면 다음과 같다.
"president obama" +havard +professor
검색 쿼리가 위와 같은 경우 query parser가 "president obama", +havard, +processor에 대해서 각각 analyzer를 실행한다. 영어처럼 단어마다 띄어쓰기를 하는 언어에서는 문제가 없는 방식이다. 하지만 최적의 형태소 결합을 찾는 mecab-ko-lucene-analyzer의 특성상 완전한 문장이 analyzer로 들어와야 정확한 형태소 분석이 보장된다. 두 가지의 방식으로 ‘이성과 감성'이라는 문장을 분석하면 다음과 같이 다른 결과가 나온다.
'이성과', '감성'을 각각 형태소 분석을 했을 경우, mecab-ko-dic 형태소 분석 결과
이(관형사), 성과(명사), 감성(명사) => 원하는 형태소 분석 결과가 아님
'이성과 감성'을 형태소 분석 했을 경우, mecab-ko-dic 형태소 분석 결과
이성(명사), 과(조사), 감성(명사)

해결 방안

모든 단어 검색을 할 경우

'+이성과 +감성'과 같이 모든 단어 포함 검색을 하고 싶은 경우, Sloppy phrase query를 사용한다. 위의 예에서도 알 수 있듯이, phrase query인 경우 완전한 구문이 analyzer로 넘어간다. 충분히 큰 slop 값을 주면 모든 문서에 대해서 검색할 수 있다. lucene query parser의 경우 다음과 같이 사용할 수 있다.
q=title:"이성과 감성"~1000

일부 단어 검색을 할 경우

phrase query를 쓰기 힘든 일부 단어 검색의 경우, 공백 문자 앞에 ,(쉼표)와 같은 특정한 기호를 넣는 꼼수로 문제를 해결했다. 다음과 같은 식이다.
q=title:(이성과, 감성)
여기서 쉼표는 텍스트가 이어지는 지점이라는 힌트를 은전한닢 형태소 분석기에 제공하는 역할을 한다. 실제로 '이성과'와 '이성과,’를 mecab-ko-dic을 통해 형태소 분석을 하면 다음과 같이 다른 결과가 나온다.
이성과
이    MM,F,이,*,*,*,*,*
성과  NN,F,성과,*,*,*,*,*
EOS
이성과,
이성  NN,T,이성,*,*,*,*,*
과    JC,F,과,*,*,*,*,*
,     SY,*,*,*,*,*,*,*
EOS
SY(Symbol)은 mecab-ko-lucene-analyzer에서 인덱스에 남기지 않기 때문에, 사용할 수 있는 꼼수이다. 이 방법에도 부작용이 있는 경우가 발견되면, 지금의 해결 법은 바뀔 수 있다.

샘플

title과 body로 구성된 데이터를 검색한다고 했을 때, 다음과 같이 sloppy query에 가중치를 주고 edismax를 사용하여, 일부 단어 검색을 하는 query를 만들 수 있다.
사용자 검색어가 ‘이성과 감성' 일 때,
title="이성과 감성"~1000^5.0 OR body="이성과 감성"~1000^3.0 OR _query_:"{!edismax qf='title^2.0 body' mm='2<75%'}이성과 감성"
이 쿼리식이 최적이라는 것이 아니라, 어디까지나 예제일 뿐입니다. 효과적인 쿼리식이나 괜찮은 예제가 있으면 댓글로 알려주시면 감사하겠습니다.

남겨진 문제

띄어쓰기 오류에서 오는 문제점

테스트 중 알게 된 예상치 못한 경우가 띄어쓰기가 없는데 여러 개의 token이 나오는 경우, 검색식이 만들어지는 방식이 좀 이상한 것이었다.
mecab-ko-lucene-analyzer의 Standard(Query|Index)Tokenizer에서는 어절에 가중치를 주기 위해서 어절 token을 유의어 개념으로 반환하는데 예를 들면 다음과 같다.
이성과 감성 => (이성과 이성) 감성
위에서보면 '이성과'와 '이성' 두 token을 position 변화 없이 (positionIncrement=0) 반환하는데, Solr의 debugQuery를 활용하여 보면, 띄어쓰기가 있는냐 없는냐에 따라, Solr에서 실제의 쿼리가 다르게 구성되는 것을 볼 수 있다.
title:(이성과, 감성) 분석 결과
"debug": {
  "rawquerystring": "title:(이성과, 감성)",
  "querystring": "title:(이성과, 감성)",
  "parsedquery": "((title:이성과 title:이성)/no_coord) title:감성",
  "parsedquery_toString": "(title:이성과 title:이성) title:감성",
...
}
위의 경우, '이성과'와 '이성'이 유의어 개념으로 올바르게 처리되고 있다. (parsedquery에서 괄호로 묶인 부분)
title:(이성과감성) 분석 결과
"debug": {
  "rawquerystring": "title:(이성과감성)",
  "querystring": "title:(이성과감성)",
  "parsedquery": "title:이성과 title:이성 title:감성",
  "parsedquery_toString": "title:이성과 title:이성 title:감성",
  ...
  }
‘이성과'와 ‘이성'이 유의어 개념이 아니라, 서로 다른 token으로 처리되고 있다.
Solr query parser가 왜 이런 결과를 내는지는 잘 모르겠다. 특별한 이유가 없는 한, 논리적으로 틀린 방식이라고 생각이 된다.
위의 문제를 해결 방안은 두 가지 정도로 생각된다.
  1. 사용자 검색어를 전처리를 통해 띄어쓰기 보정을 한 후에, Solr query를 구성
  2. 띄어쓰기 단위가 아니라, 형태소 분석기에서 나온 형태소 단위로 처리하는 query parser를 작성
일단 은전한닢 프로젝트에서는 작업양이 적게 느껴지는 첫 번째 방법을 통해서 문제를 해결할 수 있는지 조사하고 있다. 관련 작업이 끝나는 대로, 이 글을 수정하거나 새로운 글을 올릴 예정이다.
Written with StackEdit.

2013년 4월 11일 목요일

mecab-ko-lucene-analyzer OpenJDK에서 사용하기

mecab-ko-lucene-analyzer가 OpenJDK 상에서는 제대로 동작을 하지 않는 문제가 발견되었습니다. 정확히는 MeCab의 JNI가 비정상적인 동작(형태소 분석 결과가 나오지 않음)을 합니다. MeCab은 Java 인터페이스를 만들기 위해서 SWIG라는 툴을 사용하는데, 이 문제가 SWIG의 문제인지 OpenJDK의 문제인지는 잘 모르겠습니다.

이것저것 시도해보다가 다음과 같이 mecab-java-0.996의 Makefile에서 gcc 최적화 옵션을 -O나 -O1으로 낮추면 정상 동작하는 것을 확인하였습니다. 뭔가 매우 찝찝하지만 일단은 여기까지 입니다. -_-a

테스트 된 환경은 다음과 같습니다.
CentOS 6.3
java version "1.6.0_24"
OpenJDK Runtime Environment (IcedTea6 1.11.1) (rhel-1.45.1.11.1.el6-i386)
OpenJDK Server VM (build 20.0-b12, mixed mode)
관련하여 더 좋은 해결 방법을 아시는 분은 알려주시면 감사 하겠습니다.

TARGET=MeCab
JAVAC=javac
JAVA=java
JAR=jar
CXX=c++
INCLUDE=/usr/lib/jvm/java-6-openjdk/include
PACKAGE=org/chasen/mecab
LIBS=`mecab-config --libs`
INC=`mecab-config --cflags` -I$(INCLUDE) -I$(INCLUDE)/linux
all:
    $(CXX) -O3 -c -fpic $(TARGET)_wrap.cxx  $(INC)
    $(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
test:
    env LD_LIBRARY_PATH=. $(JAVA) test
clean:
    rm -fr *.jar *.o *.so *.class $(PACKAGE)/*.class

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

2013년 2월 21일 목요일

Cent OS 5.9에서 MeCab 및 mecab-ko-dic 설치하기

 주로 Ubuntu 12.10에서 작업과 테스트를 했는데, Cent OS 5.9에서 테스트 해보니, 설치가 쉽지 않네요. Cent OS 5.9가 gcc와 autotools 버전이 낮아서 생기는 문제로 생각됩니다. 삽질 끝에 설치 방법 올립니다. 참고로 Cent OS 6.3에서는 별 문제 없이 MeCab 및 mecab-ko-dic 설치가 가능합니다.

MeCab 설치

일단, Cent OS 5.9의 기본 gcc에서는 다음과 같은 에러를 내면서, 컴파일이 안됩니다.
libtool: link: g++ -O3 -Wall -o .libs/mecab mecab.o  ./.libs/libmecab.so -lpthread -lstdc++ -Wl,-rpath -Wl,/usr/local/lib
./.libs/libmecab.so: undefined reference to `__sync_val_compare_and_swap_4'
collect2: ld returned 1 exit status
make[2]: *** [mecab] 오류 1
...
검색을 좀 해보니, 그냥 gcc 버전을 올리는 것이 답인 듯 하여, 다음과 같이 gcc 4.4.7을 설치 하였습니다.
# yum install gcc44 gcc44-c++
이후, 다음과 같이 컴파일 및 설치를 진행하시면 잘됩니다.
$ cd mecab-0.994
$ ./configure CXX=g++44
$ make
# make install

mecab-ko-dic 설치

mecab-ko-dic도 autotools의 버전 문제로 ./configure가 안됩니다. 다음과 같이 autoreconf로 configure 파일을 다시 작성하신 후 설치하시면 됩니다.
$ tar xvzf mecab-ko-dic-1.1.2-20130219.tar.gz
$ cd mecab-ko-dic-1.1.2-20130219
$ autoreconf -vi
$ ./configure
$ make
$ make install