개인적으로 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의 경우 +를 삭제 해주면 된다. 다음에는 다중 검색에 대해 알아보자.