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가 왜 이런 결과를 내는지는 잘 모르겠다. 특별한 이유가 없는 한, 논리적으로 틀린 방식이라고 생각이 된다.
위의 문제를 해결 방안은 두 가지 정도로 생각된다.
- 사용자 검색어를 전처리를 통해 띄어쓰기 보정을 한 후에, Solr query를 구성
- 띄어쓰기 단위가 아니라, 형태소 분석기에서 나온 형태소 단위로 처리하는 query parser를 작성
Written with StackEdit.
댓글 없음:
댓글 쓰기