'CustomScoreQuery'에 해당되는 글 2건

  1. 2010.01.06 Lucene CustomScoreQuerySample #2 - 응용편 -
  2. 2009.12.24 Lucene 3.0 그리고 CustomScoreQuery. (2)
우선 이 포스트에 나오는 sample 소스는
http://blog.mono-koubou.net/wp-content/uploads/2008/01/valuesourcequerysample.txt
의 소스를 살짝 수정한 소스 입니다.

앞선 포스트에서는 루씬의 CustomScoreQuery 기초적인 사용법을 보았습니다.

이번에는 이 CustomeScoreQuery를 이용해서 조금 응용을 해보겠습니다.

아래 이미지를 봐주세요.



바로 집을 기준으로 거리가 5이내에 있는 스시 집을 찾아보도록 하겠습니다.
일단, 위와 같은 결과를 얻으려면 일단 스시인 집들을 찾고 그 안에서 각 좌표를 통해 거리를 계산해야 할 것 입니다.
거리를 구하는 공식은.. 피타고라스의 정리를 이용하면 아래와 같이 구해집니다.
(x'-x)^2 + (y' - y)^2 = 거리^2
에서 거리 = sqrt((x'-x)^2 + (y' - y)^2) 가 됩니다.

이것을 이용해 보겠습니다.

일단 코드입니다.


DistanceQuerySample.java
하나하나 살펴보겠습니다. 일단, main 메서드 입니다.


여기서는 "스시"집 중에서 집(5,5)를 기준으로 거리 5이내에 있는 스시집을 찾고자 하는 질의 입니다.
색인 데이터는

이렇게 각 가게의 이름과 좌표를 주고 있습니다.

색인하는 메서드는 이전 포스트에 있으니까 넘어가고 바로
search메서드를 살펴보겠습니다.


좌표와 거리를 받아서 쿼리 구문을 만듭니다.


이 쿼리에 의해서 "스시"집들이 검색이 될 것 입니다.
CustomQuery는 앞에서 말씀드렸지만 기본 질의 쿼리와 valueSource 쿼리를 사용해서 점수를 계산합니다.
기본질의 쿼리의 점수와 valueSourceQuery의 점수를 마음대로 사용 할 수 있지요.

그런데, 이상한 클래스가 하나 있습니다.
DistanceFunction 이라는 클래스입니다.
이 클래스는 아래와 같은 모양을 갖습니다.

보시면 아시겠지만 이 클래스는 FloatFieldSource를 상속받고 있습니다. 앞에서, CustomScoreQuery를 사용 할 때
FloatFieldSource를 사용해서 ValueSourceQuery를 만들었던 것 기억이 나시나요?



위 구문으로 ValueSourceQuery가 던져주는 score는 count필드의 값 그 자체가 되었었습니다.
현재 우리는 특정 필드의 값 자체가 필요한 것이 아니고
그 필드의 값 (좌표)를 통해 거리를 계산해야 하기 때문에 그것을 계산하기 위한 DistanceFunction 클래스를 만들었고
이것을 이용해 ValueSourceQuery를 만들어야하기 때문에 FloatFieldSource를 상속 받았습니다.

그럼 거리를 계산하는 메서드를 보겠습니다.
IndexReader를 통해서 해당 필드의 값을 모두 뽑아 내고 있습니다. 여기서는 좌표값들이 나오겠죠..

그런데 여기서 return값이 계산 된 거리 값일 것 같았는데 DocValues 입니다.
CustomScoreQuery내부적으로는 ValueSourceQuery를 사용해서 ValueSourceQuery의 score를 계산하는데, 이 ValueSourceQuery는
ValueSourceScore를 계산하고 이때 사용 되는 것이 DocValues입니다. 때문에, 위 메서드에서 DocValues를 상속한
DistnaceDocValues를 리턴해주고 있는 것 입니다.

실제적으로 IndexReader를 통해서 뽑아온 좌표들을 사용해서 기준점과 거리를 계산하고 그 값을
리턴해주는 클래스는 아래의 클래스입니다.

이 클래스에서는 기준점과 대상점을 받아서 거리를 계산하고 있습니다.
public float floatVal(int doc) 메서드의 이름으로 유추해볼때 i번째 검색된 document에 대한 거리 값을 리턴 할 수
있도록 되어 있는 것 같습니다.

distance = (float)d_ - distance;

가 들어가 있는 것은 기준 되는 거리(5) 에서 계산 된 거리를 뺄 경우 가장 가까울수록 큰 값이 나오기 때문입니다.
이 값 그 자체가 score가 되기 때문에 위와 같이 distance를 계산해서 넘겨주면 가장 가까운 가게가 가장 먼저
나오게 됩니다.

distance = distance > 0f ? distance : 0f;

이 부분이 들어가 있는 이유는 5이내의 가게를 찾는 것이기 때문에 거리가 5 이상이 되는 것들은 맨 밑으로 내려버리기 위함입니다.

위와 같이 DocValues를 상속받아 클래스를 만들면 원하는 값으로 점수를 마음대로 산정 할 수 있게 됩니다.

위 클래스 실행 결과는 아래와 같습니다.
1.1985767 : 스시 / 7,7
1.1038789 : 스시 / 5,2
0.48399264 : 스시 / 6,9
0.41801658 : 스시 / 2,8
0.0 : 스시 / 1,9

Posted by 용식
http://softwaregeeks.org/blog/271

트랙백을 남겨주신 짐승님의 글을 보고 ... ^^

항상 검색 엔진의 인덱스 파일의 용량이 대용량으로 가면서 문제 되는 것이
정렬 문제 였다.

그러던 중 짐승님이 남겨주신 트랙백의 글을 보고 정신이 탁 트여지는 것을 느꼈다.

예전에도 루씬의 DocScore를 가중치나 계산 공식 변경등을 통해 수정 할 수 있다는 것은 알았었는데
그 score자체가 정렬과 연관이 지어지지를 않고 있었다.

그런데 짐승님의 (아 이거 어감이 정말..-_-;;;) 글 http://softwaregeeks.org/blog/271 을 보고나니
뭔가 탁~~~ 하고 깨이는 느낌..

나는 왜 저렇게 생각의 전환이 안 되는거지... -.-;

안그래도 회사에서 로그 분석을 간단하게 루씬으로 구현하면서
이 정렬 문제가 대두되고 있었는데, 바로 한번 적용을 해보았다.

바로 CustomScoreQuery






아래 예제 클래스에서 customScore의 float valSrcScore는 ValueSourceQuery의 점수고 이 ValueSourceQuery는
FieldScoreQuery가 extends하여 구현하고 있다. 대략 보면.. count 필드의 값이 내부적으로 정규화 과정을 거쳐서
점수로 환산되고 이것이 subQueryScore (루씬의 일반적인 랭킹 점수) 와 합산 되는 듯 하다.

FieldScoreQuery.Type은 4가지가 존재하는데 각각의 타입에 따라서 필요한 RAM의 양이 다르다고 나와있다.

INT는 4 * maxDocs bytes
FLOAT은 8 * maxDocs bytes
SHORT는 2 * maxDocs bytes
BYTE는 1 * maxDocs bytes..

아마 각 타입에 따른 정규화 과정 때문에 그런 것 같기도 하고..

아무튼 자세히 파보지는 않아서 정확히는 모르겠지만...
위 count 필드가 검색회수라고 가정하면 위의 쿼리로는 가장 검색 회수가 많은 순 부터
검색이 된다.

기본적으로 검색을 다 해 놓은 결과 SET을 가지고 다시 정렬을 하는 것이 아니기 때문에
Sort를 사용하는 것 보다 훨씬 빠른 결과를 가져 올 수 있다.

짐승님이 걸어주신 트랙백 덕분에
너무 좋은 것을 알게 되었습니다. 감사합니다. ^^

이 글 자체는 Lucene 3.0 하고는 큰.. 관계는 없겠네요..

Posted by 용식