본문으로 바로가기
반응형

루씬에서 가장 기본이 되는 query는 TermQuery로 일치하는 문자를 검색할때 사용합니다.

그외에도 확장된 성격을 띄는 query들을 추가적으로  제공하는데 그중에 SpanQuery에 대해 설명합니다.

(찾아보니 한글로 정리된글은 찾기가 어렵더군요.)


이 글은 하기 링크의 원문을 번역 및 의역 하였습니다.

https://lucidworks.com/post/the-spanquery/


SpanQuery는 문서를 찾을때 내부의 위치 제한을 줄 수 있습니다. 이는 위치를 제한한다는 점에서 PhraseQuery 또는 MutilPhraseQuery와 매우 유사하지만

 SpanQuery가 더 큰 표현력을 가집니다.

 기본 SpanQuery의 단위는 SpanTermQuerySpanNearQuery 입니다.

 SpanTermQuery는 SpanQuery의 기본이 되는 Query로 TermQuery처럼 field, term, boost를 넘겨줄수 있습니다.

 또한 SpanQuery를 결합하여 사용하는 SpanNearQuery같은걸 사용할때 이를 구성하는 기본 단위가 됩니다.

 

 SpanNearQuery는 주어진 거리 내에서 여러 SpanQuery를 찾습니다. span이 지정된 순서와도 일치할때만 찾게 할 수도 있고,

 순서와 상관없이 거리만으로도 찾도록 할수 있습니다.

 SpanNearQueyr는 여러개의 TermQuery로 구성되거나, 다른 SpanNearQuery 포함할수도 있습니다.

 포함된 SpanNearQuery 역시 또다른 TermQueyr나 SpanNearQuery로 구성되어 있을 수 있겠죠?


※모든 예제는 Kotlin으로 작성되었습니다.

SpanNearQuery(arrayOf<SpanQuery>(
            SpanTermQuery(Term(Field, "lucene")),
            SpanTermQuery(Term(Field, "dog"))
    ),5, true)


The Lucene was made by Doug Cutting

     0------>

     1---------->

     2-------------->

     3------------------>


SpanNearQuery의 생성자로 찾을 Term의 배열과, 거리, 배열 순서와 일치하게 배치된것만 찾을지 (order)에 대해서 설정할 수 있습니다.

또한 SpanNearQuery는 builder를 제공하므로 builder로 해당 값들을 설정 할 수도 있습니다.


거리를 2로 설정한다면 용어가 순서에 맞지 않게 돼있지 않더라도 충분히 검색하여 찾아낼 수 있습니다.

val spanNear = SpanNearQuery(arrayOf<SpanQueyr>(
            SpanTermQuery(Term(Field, "lucene")),
            SpanTermQuery(Term(Field, "dog"))
    ),5, true)

SpanNearQuery(arrayOf<SpanQueyr>(
            spanNear,
            SpanTermQuery(Term(Field, "hadoop"))
    ),4, true)

The Lucene was made by Doug Cutting and the great Hadoop was

                                           4--------------------------->


위 예제는 SpanNearQuery 내부에 또다른 SpanNearQuery를 넣는 예제 입니다.

이외에도 span query를 결합하기 위해 지원하는 여러 클래스가 있습니다.

  • SpanOrQuery

 SpanQuery의 배열을 가지고 하나라도 일치하면 match 시킵니다.

  • SpanNotQuery

 두개의 SpanQueyr를 param을 받습니다. 첫번째 param과는 match 하지만, 두번재 param과는 일치하지 않는 것만 골라 냅니다. 즉 param1은 만족하나, param2는 만족하지 않아야 할때 사용합니다.

예를 들어 "george w. bush"란 문구와 "grorge bush" 중에 w.가 없는 "george bush"만 찾고 싶을때 이 query를 사용할 수 있습니다.

  • SpanFirstQuery

Field의 처음부터 시작하여 n개 까지에서 match되는 query를 찾습니다.

이는 SpanPositionRangeQuery에서 start값을 0으로 고정한 simple 버전 입니다.

 즉 end값만 설정할 수 있습니다.


val spanNear1 = SpanNearQuery(arrayOf(
            SpanTermQuery(Term(FIELD, "lucene")),
            SpanTermQuery(Term(FIELD, "doug"))),
            3,
            true)

val spanNear2 = SpanNearQuery(arrayOf(
            SpanTermQuery(Term(FIELD, "was")),
            SpanTermQuery(Term(FIELD, "cutting"))),
            3,
            true)

SpanNearQuery(arrayOf(spanNear1, spanNear2),
            0,
            true)


The lucene was made by Doug Cutting

         --------------------->

                    --------------------->

두번째 span이 첫번째 span의 시작과 끝 사이에 위치한다면 두 span의 거리는 0으로 판단되어 일치될 수 있습니다.

따라서 was 대신에 made나 by를 쓰더라도 match 됩니다.

만약에 두번째 span이 Cutting에서 시작한다 하더라도 거리가 0이므로 역시 match 됩니다.


거리(Distance)는 span1의 끝에서 span2의 시작까지의 사이를 나타냅니다.

하지만 순서에 대한 제한은 (true로 설정)은 "첫번째 span의 시작(start) 이후에 두번째 span이 시작되어야 한다"만 만족하면 되기 때문에

위 문장과 같은 현상이 일어나면 match로 처리 됩니다.

("첫번째 span이 시작-끝 된 이후에 두번째 span이 시작되어야 한다"가 아닙니다.)

 

다른 예로 아래와 같은 문장이 있다고 있다고 가정 합니다.

cats and dogs and cats and cats 

그리고 아래와 같은 코드로 query 합니다.

SpanNearQuery(arrayOf(
            SpanTermQuery(Term(FIELD, "cats")),
            SpanTermQuery(Term(FIELD, "dogs"))),
            10,
            flase)


이때 결과를 highlight 한다고 하면 결과는 아래와 같습니다.

cats and dogs and cats and cats

마지막 cats는 highlight에서 빠졌습니다.

왜일까요?


cats and dogs and cats and cats

1<--------->

2             <--------->

1번 span의 경우 "cats and dogs"를 검색하고 그 다음 span은 dogs 부터 시작하여 cats까지 검색됩니다.

하지만 그 이후 역시 두번째 등장한 cats 이후부터 검색되어 span 조건을 만족해야 하기 때문에 마지막 cats는 match 되지 않습니다.

반응형