## 목차 ##



## 1. 필드 캐시 ##

  • 문서의 특정 필드 값을 빠르게 조회해야 할 경우에 사용

    • 특정 필드의 값을 순차적으로 조회할 목적으로 만든 루씬 내부 API
  • 필드 캐시를 사용하기 위해서는 해당 필드에 하나의 텀만 들어있어야한다.

    • Index.NOT_ANALYZED 혹은 Index.NOT_ANALYZED_NO_NORMS



(1) 모든 문서의 필드 값 불러오기

  • 필드 캐시를 사용하면 색인 모든 문서의 특정 필드 값 배열을 받아올 수 있다.
float[] weights = FieldCache.DEFAULT.getFloats(reader, "weight");

float value = wegihts[docID];
  • 필드캐시 초기화는 색인 크기에 따라 시간이 오래 걸릴 수 있다.

  • 필드 캐시는 많은 메모리를 잡아먹을 수도 있다.

    • 특히 String



(2) 세그먼트별 IndexReader

  • 루씬 2.9부터 검색, 정렬은 세그먼트 단위로 동작한다.



## 2. 검색 결과 정렬 ##

  • 검색 결과는 기본적으로 연관도 점수의 내림차순 정렬

  • 루씬에서는 사용자 정의 정렬 기법 제공

    • 필드 캐시를 사용한다.
    • ex) 특정 필드값을 기준으로 정렬



(1) 필드 값으로 정렬

  • IndexSearcher.search(Query, Filter, int, Sort) 메소드 사용
...

TopDocs resultDocs = searcher.search(query, null, 10, sort);

for(ScoreDoc scoreDoc : resultDocs.scoreDocs) {
    int docID = scoreDoc.doc;
    Document doc = searcher.doc(docID);
    System.out.println(doc);
}

...



(2) 연관도 순서로 정렬

  • 루씬의 기본 정렬 설정
    • search(query, null, 10, null) 혹은 search(query, 10)
    • 연관도 점수가 같으면 docID 순서로 정렬



(3) 색인 순서로 정렬

  • 문서 ID 순서로 정렬

  • search(query, null, 10, Sort.INDEXORDER)



(4) 필드 값으로 정렬

  • 정렬하고자 하는 필드에 하나의 텀만 있어야한다.

  • 필드값 기준 정렬은 기본적으로 오름차순

  • SortField 객체 사용

...

Sort sort = new Sort(new SortField("category", SortField.STRING));
//Sort sort = new Sort(new SortField("category", SortField.STRING, true)); //역방향 인자로 true를 지정하면 내림차순 정렬

searcher.search(query, null, 10, sort);

...



(5) 여러 필드 값으로 정렬

  • Sort 객체 생성 시 여러개의 SortField를 넘겨줄 수 있다.
Sort sort = new Sort(new SortField("category", SortField.STRING),
                        SortField.FIELD_SCORE,
                        new SortField("pubmonth", SortField, true));



## 3. 여러 개의 필드를 동시에 검색 ##

  • MultiFieldQueryParser 클래스 사용
...

//title 혹은 subject 필드에 "lucene"을 포함하는 쿼리 생성
QueryParser parser = new MultiFieldQueryParser(Version.LUCENE_30,
                                                new String[]{"title", "subject"},
                                                new SimpleAnalyzer());

//title과 subject필드 모두에 "lucene"을 포함하는 쿼리 생성
QueryParser parser2 = new MultiFieldQueryParser(Version.LUCENE_30,
                                                new String[]{"title", "subject"},
                                                new BooleanClause.Occur[]{Occur.MUST, Occur.MUST},
                                                new SimpleAnalyzer());

Query query = parser.parse("lucene");

...



## 4. 스팬 질의 ##

  • 스팬(span)이란?

    • 문서 필드에서 토큰이 있는 위치 정보
  • 루씬은 SpanQuery를 기반으로 하는 여러가지 하위 클래스들을 내장하고 있다.

    • SpanTermQuery
    • SpanFirstQuery
    • SpanNearQuery
    • SpanNotQuery
    • FieldMaskingSpanQuery
    • SpanOrQuery
  • 검색어 토큰의 위치 정보를 같이 검색

  • PhraseQuery에 비해 위치정보를 좀 더 명확하게 표현

    • PhraseQuery는 slop값 지정까지만 가능
  • 문서를 찾아내는거에 더해 텀의 위치정보 계산이 추가되어 처리량이 많다.

    • ex) SpanTermQuery는 텀을 포함하는 문서를 찾아낸 뒤 텀의 위치정보까지 계산한다.



(1) SpanTermQuery

  • 모든 SpanQuery 하위 클래스를 사요하기 위한 시작 질의

  • 모든 SpanQuery하위 클래스는 SpanTermQuery 객체를 넘겨받아 동작한다.

...
doc.add(new Field("field",
        "the quick brown fox jumps over the lazy dog",
        Field.Store.YES,
        Field.Index.ANALYZED));

doc.add(new Field("field",
        "the quick red fox jumps over the sleep cat",
        Field.Store.YES,
        Field.Index.ANALYZED));
...

Term term1 = new Term("field", "brown");
Term term2 = new Term("field", "red");

SpanTermQuery brown = new SpanTermQuery(term1);
SpanTermQuery red = new SpanTermQuery(term2);



위에서 만들어놓은 색인 문서와 질의 객체를 사용해 SpanQuery의 종류를 하나씩 보자.



(2) SpanFirstQuery

  • 필드의 맨 앞에서 일정 범위 안에 있는 문서 검색
//brown 스팬텀쿼리 객체를 넘겨주고 필드의 앞에서 2번째 위치내에 있는 문서 검색
SpanFirstQuery sfq = new SpanFirstQuery(brown, 2);
searcher.search(sfq, 10);

sfq = new SpanFirstQuery(brown, 3);
searcher.search(sfq, 10);

"the quick brown fox jumps over the lazy dog" 구문에서 brown은 3번째 위치에 존재하므로 첫 번째 검색 결과문서는 0개이고 두 번째 검색 문서 결과는 1이다.



(3) SpanNearQuery

  • PhraseQuery와 마찬가지로 가까이 있는 텀을 찾아준다.
    • 일정 거리 안에 있는 스팬을 찾아준다.
    • 순서대로 위치해야 하는지 아닌지를 설정 가능하다.(inOrder 값)
SpanQuery[] quick_brown_dog = new SpanQuery[]{quick, brown, dog};

//quick,brown,dog가 스팬 없이(0), 순서대로(true) 오는 문서 검색
SpanNearQuery snq = new SpanNearQuery(quick_brown_dog, 0, true);
searcher.search(snq, 10);
//검색 결과 0건

//quick,brown,dog가 사이 스팬이 5 이내이고 순서대로 오는 문서 검색
snq = new SpanNearQuery(quick_brown_dog, 5, true);
searcher.search(snq, 10);
//검색결과 1건

이외에도 SpanNotQuerySpanOrQuery가 있는데 쓸 일이 있을까 싶다. 있으면 찾아보자.



## 5. 검색 필터 ##

  • 필터를 적용하면 검색 대상을 줄여준다.

    • 색인의 일부 문서만 대상으로 검색 실행
    • 이전에 검색한 결과 안에서만 검색하는 결과 내 검색 기능 구현
  • IndexSearch(Query, Filter, int, Sort) 메소드에 필터 전달하여 검색



(1) TermRangeFilter

  • 문자열 필드에 적용하는 필터

  • TermRangeQuery와 동일하나 연관도 점수는 계산하지 않는다.

  • 특정 필드 값의 문자열 범위 지정

//title 필드의 값이 'a'~'c'로 시작하는 문서만 검색하는 필터. a포함(true), c포함(true)
Filter filter = new TermRangeFilter("title", "a", "c", true, true);

//title 필드의 값이 'h'로 시작하는 문서만 검색하는 필터.
Filter filter2 = new TermRangeFilter("title", "h", null, true, false);

마지막 인자 두 개는 includeLower, includeUpper이며 범위의 시작 값, 끝 값을 포함할 것인지의 여부를 지정한다.



(2) NumericRangeFilter

  • 숫자 값이 들어있는 필드의 범위로 필터링

  • NumericRangeQuery와 동일하나 연관도 점수를 계산하지 않는다.

//pubmonth 필드의 값이 2001년6월~2001년9월 사이인 문서만 검색하는 필터
Filter filter = new NumericRangeFilter("pubmonth", 200106, 200109, true, true);



(3) FieldCacheRangeFilter

  • TermRangeFilter, NumericRangeFilter 같은 기능이지만 필드 캐시를 사용한다.
Filter filter1 = FieldCacheRangeFilter.newStringRange("title", "d", "j", true, true);
Filter filter2 = FieldCacheRangeFilter.newFloatRange("score", 1.0f, 5.0f, false, false);



(4) QueryWrapperFilter

  • 쿼리를 필터로 변환
Query query = new TermQuery("title", "lucene");
Filter filter = new QueryWrapperFilter(query);



(5) SpanQueryFilter

  • QueryWrapperFilter와 같은 역할을 하지만 추가적으로 스팬 관련 정보를 유지한다.
    • QueryWrapperFilter보다 느리므로 굳이 스팬 정보가 필수가 아니라면 사용하지 않는것이 좋다.



이외에도 루씬 공식 문서를 보면 다양한 내부 필터를 지원한다. 뿐만 아니라 contrib 모듈에서는 여러 종류의 필터가 제공된다.



(6) 필터와 BooleanQuery

  • 필터 기능은 BooleanQuery에서 조건을 추가하는 것으로 모두 대신할 수 있다.
    • 결과로 받는 문서는 같다.
    • CachingWrapperFilter등을 활용하면 필터를 캐시하고 재사용할 수 있다.
    • 검색 대상 문서가 다르기 때문에 idf 점수가 달라진다.
    • CachingWrapperFilter등을 활용하면



## 6. 다수의 루씬 색인 검색 ##

(1) MultiSearcher

  • 여러개의 색인 각각 IndexSearcher를 따로 사용
    • 각 색인별로 결과를 취합하고 문서를 정렬해서 반환
...

IndexSearcher[] searchers = new IndexSearcher[2];
searchers[0] = new IndexSearcher(directory0);
searchers[1] = new IndexSearcher(directory1);

//IndexSearcher[] 배열을 MultiSearcher의 생성자에 넘긴다.
MultiSearcher searcher = new MultiSearcher(searchers);

TopDocs hits = searcher.search(query, 10);

...

(2) ParallelMultiSearcher

  • MultiSearcher와 같은 기능이지만 개별 IndexSearcher마다 스레드를 활용해 검색한다.
    • 멀티코어이면서 개별 인덱스가 다른 디스크에 저장된 환경에서 유용



## 7. 텀 벡터 활용 ##



## 8. FieldSelector로 필드 선택 ##



## 9. 검색 중단 ##

'프레임워크 > 루씬(Lucene)' 카테고리의 다른 글

(루씬) 3 - 검색(Search)  (0) 2020.05.16
(루씬) 2 - 색인(Indexing)  (0) 2020.05.16
(루씬) 1 - 루씬과의 만남  (0) 2020.05.16

+ Recent posts