개발관련/Lucene,ElasticSearch 2015. 11. 23. 18:28

개인적으로 Lucene을 사용하다보면 검색 쿼리를 객체로 컨트롤 하기가 귀찮아 진다. 여기서 객체란 BooleanQuery, TermQuery, FuzzyQuery, WildCardQuery등등 있다. 이런것들을 이용하여 쿼리를 만들 수 있으나 String 형태로 쿼리를 만들 수도 있다. 이번엔 그런 것들을 해보자. 



먼저 Lucene도 3가지 옵션을 제공한다. Must, Should, MustNot 이 옵션 세가지를 제공한다. 


1. Must - And와 같다. 

2. Should - or와 같다. 

3. Must Not - Not And와 같다. 


그리고, 쿼리는 다음과 같은 형태로 변환이 된다. 


(+text:cross) ((html:good) (+html:boat))  이런식으로 쿼리가 변환이 된다. 이걸 다시 풀어보면..

text필드의 cross를 And 검색하라. 

html필드를 good을 or로 검색하고 html에 boat는 and로 검색하라. 그리고 이전체를 or로 검색하라 . 라는 결론이 된다. 


물론 단일 term의 경우 and나 or나 결과는 같다. 하지만 ((html:good) (+html:boat)) 이 구문의 경우 (+html:good +html:boat) 이런 형태로도 나올 것이다. 일종의 sql의 where과 흡사하다. 


위에 예제와 같이 여러개의 쿼리를 필요 할때는 BooleanQuery를 루씬에서 제공한다. 그럼 만들어보자. 



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
 //생략//////////////////////////////////////////
    public String tempAndAnalyze(String string[], String field, Analyzer analyzer)
            throws IOException {
        StringBuffer buffer = new StringBuffer();
 
        buffer.append("(");
        for(String str : string){
                buffer.append("+");
                // buffer.append(field);
                // buffer.append(":");
                buffer.append(str).append(" ");
            
        }
        
        buffer.append(")");
 
 
 
        return buffer.toString();
    }
 
    @Test
    public void testHtmlBasicSearchData2() {
        String andWordSearch = "cross sectional";
        
        if (andWordSearch != null && andWordSearch != "") {
                try {
//                    searchIndex(andWordSearch, textField);
                    String queryStr = tempAndAnalyze(andWordSearch.split(" "), "text");
                    Query andQuery = new QueryParser(Version.LUCENE_36, "text",
                            new StandardAnalyzer(Version.LUCENE_36)).parse(queryStr); // #B
                    
                    TopDocs hits = searcher.search(andQuery, searcher.maxDoc());
                    dumpHits(searcher, hits, "text");
                } catch (ParseException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                
 
        }
        
    }
cs


위에 설명한 대로 cross sectional 쿼리를 String으로 만들고 그것을 다시 stringbuffer에 저장해서 QueryParser로 전달했다. 갠적으론 이방법을 많이 쓴다. 


여기서 tip 한개더. 루씬은 stanardAnalyzer를 space+stop word(내부에 저장) 를 기반으로 단어를 나눈다. 이때 중요한 점은 lowcase는 적용을 안한다는 사실이다. 이 때문에 standard를 쓸 시 필히 대소문자를 구분해야한다. 


or문의 경우 tempAnalyze의 경우 +를 삭제 해주면 된다.  다음에는 다중 검색에 대해 알아보자. 

posted by 제스트
: