자발적고난 (부제: 눈뜬쉑이들의 세상!!!)
Fields
Lucene supports fielded data. When performing a search you can either specify a field, or use the default field. The field names and default field is implementation specific.
You can search any field by typing the field name followed by a colon ":" and then the term you are looking for.
As an example, let's assume a Lucene index contains two fields, title and text and text is the default field. If you want to find the document entitled "The Right Way" which contains the text "don't go this way", you can enter:
title:"The Right Way" AND text:go
or
title:"Do it right" AND right
Since text is the default field, the field indicator is not required.
Note: The field is only valid for the term that it directly precedes, so the query
title:Do it right
Will only find "Do" in the title field. It will find "it" and "right" in the default field (in this case the text field).
Term Modifiers
Lucene supports modifying query terms to provide a wide range of searching options.
Wildcard Searches
Lucene supports single and multiple character wildcard searches within single terms (not within phrase queries).
To perform a single character wildcard search use the "?" symbol.
To perform a multiple character wildcard search use the "*" symbol.
The single character wildcard search looks for terms that match that with the single character replaced. For example, to search for "text" or "test" you can use the search:
te?t
Multiple character wildcard searches looks for 0 or more characters. For example, to search for test, tests or tester, you can use the search:
test*
You can also use the wildcard searches in the middle of a term.
te*t
Note: You cannot use a * or ? symbol as the first character of a search.
Fuzzy Searches
Lucene supports fuzzy searches based on the Levenshtein Distance, or Edit Distance algorithm. To do a fuzzy search use the tilde, "~", symbol at the end of a Single word Term. For example to search for a term similar in spelling to "roam" use the fuzzy search:
roam~
This search will find terms like foam and roams.
Starting with Lucene 1.9 an additional (optional) parameter can specify the required similarity. The value is between 0 and 1, with a value closer to 1 only terms with a higher similarity will be matched. For example:
roam~0.8
The default that is used if the parameter is not given is 0.5.
Proximity Searches
Lucene supports finding words are a within a specific distance away. To do a proximity search use the tilde, "~", symbol at the end of a Phrase. For example to search for a "apache" and "jakarta" within 10 words of each other in a document use the search:
"jakarta apache"~10
Range Searches
Range Queries allow one to match documents whose field(s) values are between the lower and upper bound specified by the Range Query. Range Queries can be inclusive or exclusive of the upper and lower bounds. Sorting is done lexicographically.
mod_date:[20020101 TO 20030101]
This will find documents whose mod_date fields have values between 20020101 and 20030101, inclusive. Note that Range Queries are not reserved for date fields. You could also use range queries with non-date fields:
title:{Aida TO Carmen}This will find all documents whose titles are between Aida and Carmen, but not including Aida and Carmen.
Inclusive range queries are denoted by square brackets. Exclusive range queries are denoted by curly brackets.
Boosting a Term
Lucene provides the relevance level of matching documents based on the terms found. To boost a term use the caret, "^", symbol with a boost factor (a number) at the end of the term you are searching. The higher the boost factor, the more relevant the term will be.
Boosting allows you to control the relevance of a document by boosting its term. For example, if you are searching for
jakarta apache
and you want the term "jakarta" to be more relevant boost it using the ^ symbol along with the boost factor next to the term. You would type:
jakarta^4 apache
This will make documents with the term jakarta appear more relevant. You can also boost Phrase Terms as in the example:
"jakarta apache"^4 "Apache Lucene"
By default, the boost factor is 1. Although the boost factor must be positive, it can be less than 1 (e.g. 0.2)
Boolean Operators
Boolean operators allow terms to be combined through logic operators. Lucene supports AND, "+", OR, NOT and "-" as Boolean operators(Note: Boolean operators must be ALL CAPS).
The OR operator is the default conjunction operator. This means that if there is no Boolean operator between two terms, the OR operator is used. The OR operator links two terms and finds a matching document if either of the terms exist in a document. This is equivalent to a union using sets. The symbol || can be used in place of the word OR.
To search for documents that contain either "jakarta apache" or just "jakarta" use the query:
"jakarta apache" jakarta
or
"jakarta apache" OR jakarta
AND
The AND operator matches documents where both terms exist anywhere in the text of a single document. This is equivalent to an intersection using sets. The symbol && can be used in place of the word AND.
To search for documents that contain "jakarta apache" and "Apache Lucene" use the query:
"jakarta apache" AND "Apache Lucene"
+
The "+" or required operator requires that the term after the "+" symbol exist somewhere in a the field of a single document.
To search for documents that must contain "jakarta" and may contain "lucene" use the query:
+jakarta lucene
NOT
The NOT operator excludes documents that contain the term after NOT. This is equivalent to a difference using sets. The symbol ! can be used in place of the word NOT.
To search for documents that contain "jakarta apache" but not "Apache Lucene" use the query:
"jakarta apache" NOT "Apache Lucene"
Note: The NOT operator cannot be used with just one term. For example, the following search will return no results:
NOT "jakarta apache"
-
The "-" or prohibit operator excludes documents that contain the term after the "-" symbol.
To search for documents that contain "jakarta apache" but not "Apache Lucene" use the query:
"jakarta apache" -"Apache Lucene"
Grouping
Lucene supports using parentheses to group clauses to form sub queries. This can be very useful if you want to control the boolean logic for a query.
To search for either "jakarta" or "apache" and "website" use the query:
(jakarta OR apache) AND website
This eliminates any confusion and makes sure you that website must exist and either term jakarta or apache may exist.
Field Grouping
Lucene supports using parentheses to group multiple clauses to a single field.
To search for a title that contains both the word "return" and the phrase "pink panther" use the query:
title:(+return +"pink panther")
Escaping Special Characters
Lucene supports escaping special characters that are part of the query syntax. The current list special characters are
+ - && || ! ( ) { } [ ] ^ " ~ * ? : \
To escape these character use the \ before the character. For example to search for (1+1):2 use the query:
\(1\+1\)\:2
Lucene in Action
이문서는 루씬을 잘 활용하기 위한 기초문서로, 루씬을 색인 구조를 이해하는 것 보다 루씬의 사용법을 이해하고 또한 루씬에서 제공되고 있는 분석기와 현재 배포되고 있는 한글분석기를 이해하는 것이 중요하다고 생각된다.
루씬은??
확장 가능한 정보검색 라이브러리이다.
1. 프로그램에 색인과 검색 기능을 추가할 수 있도록 지원
2. 오랜 기간 많은 사람들이 사용하며 능력과 성능을 인정
3. 자바로 구현된 오픈소스
![]()
그림 1일반적인 루씬 활용 방법
색인과 검색
API 의 예제 소스
| Analyzer analyzer = new StandardAnalyzer(); // Store the index in memory: Directory directory = new RAMDirectory(); // To store an index on disk, use this instead: //Directory directory = FSDirectory.getDirectory("/tmp/testindex"); IndexWriter iwriter = new IndexWriter(directory, analyzer, true); iwriter.setMaxFieldLength(25000); Document doc = new Document(); String text = "This is the text to be indexed."; doc.add(new Field("fieldname", text, Field.Store.YES, Field.Index.TOKENIZED)); iwriter.addDocument(doc); iwriter.optimize(); iwriter.close(); // Now search the index: IndexSearcher isearcher = new IndexSearcher(directory); // Parse a simple query that searches for "text": QueryParser parser = new QueryParser("fieldname", analyzer); Query query = parser.parse("text"); Hits hits = isearcher.search(query); assertEquals(1, hits.length()); // Iterate through the results: for (int i = 0; i < hits.length(); i++) { Document hitDoc = hits.doc(i); assertEquals("This is the text to be indexed.", hitDoc.get("fieldname")); } isearcher.close(); directory.close(); |
색인
| // indexWriter를 생성한다. 경로와 분석기를 넘겨줌 IndexWriter writer = new IndexWriter(indexDir,new StandardAnalyzer(), true); writer.setUseCompoundFile(false); // 색인에 추가될 Document 생성 Document doc = new Document(); //Document에 필드 추가 //색인에 Document 추가 |
검색
| //FSDirectory 생성 Directory fsDir = FSDirectory.getDirectory(indexDir, false); //IndexSearcher 생성 IndexSearcher is = new IndexSearcher(fsDir); /* query 객체를 생성한다. Query org.apache.lucene.queryParser.QueryParser.parse(String query, String field, Analyzer analyzer) throws ParseException 들어온 쿼리가 넘겨진 분석기에 의해 분석된다. */ Query query = QueryParser.parse(q, "contents", new StandardAnalyzer()); //검색한다. //결과에 본문은 들어가지 않는다. 결과에 포함된 문서ID의 목록만을 가져옴 Hits hits = is.search(query); |
핵심 색인 클래스
| 클래스 | 목적 |
| IndexWriter | 색인을 총괄하는 캘르스, 새로운 색인을 만들고, 추가하는 작업 |
| Directory | 색인을 저장할 저장소(RAMDirectory, FSDirectory, JDBCDirectory) |
| Analyzer | 분석하도록 지정한 모든 텍스트는 분석기를 거친다. |
| Document | 색인에 추가된는 데이터의 단위 |
| Field | 색인에 추가되는 내용은 Document 인스턴스의 Filed형태로 추가되어야함 Keyword : 분석X, 검색O, 저장O (ex. 문서의 ID, 파일경로, 날짜 사람이름 등) UnIndexed : 분석X, 검색,X, 저장O (ex. 요약문 작성시) UnStored : 분석O, 검색O, 저장X Text : 분석O, 검색O, 저장?(String or Reader 여부에 따라) |
핵심 검색 클래스
| 클래스 | 목적 |
| IndexSearcher | 색인을 검색할 때 꼭 사용해야하는 클래스이며, 여러종류의 search() 메소드를 지원 |
| Term | 색인의 내부에서 단어를 의미하는 가장 기본적인 요소. 하나의 텀은 하나의 이름과 하나의 단어로 이루어진다. Query q = new TermQuery(new Term("contents","lucene")); Hits hits = is.search(q); |
| Query | 루씬에서 검색어를 지정할 때 Query 사용, TermQuery, BooleanQuery, PhraseQuery, PrefixQuery, PhrasePrefixQuery, RangeQuery, FilterQuery, SpanQuery 등 |
| Hits | 검색 결과를 담고 있는 클래스 |
| Document document = new Document(); document.add(new Field("area", area, Store.YES, Index.UN_TOKENIZED)); document.add(new Field("vmag", vmag, Store.YES, Index.UN_TOKENIZED)); document.add(new Field("count", count, Store.YES, Index.NO)); document.add(new Field("data", data, Store.YES, Index.NO)); writer.addDocument(document); |
Field(필드명, 변수명, 저장옵션, 인덱스옵션)
- 필드명 : 어떤 이름의 필드에 저장 할 것인지를 정한다.
- 변수명 : 해당 필드명에 들어갈 값.
- 저장옵션 : 전체 값을 인덱스에 저장할것인지 여부
- Store.YES : 인덱스를 할 값 모두를 인덱스에 저장한다. 검색결과 등에서 꼭 보여야 하는 내용이라면 사용한다.
- Store.NO : 값을 저장하지 않는다. Index 옵션과 혼합하여, 검색은 가능하고, 원본 글이 필요없을 경우 사용될 수 있다.
- Store.COMPRESS : 값을 압축하여 저장한다. 저장할 글의 내용이 크거나, 2진 바이너리 파일 등에 사용한다.
- 인덱스 옵션 : 검색을 위한 인덱스 생성 방식을 정한다.
- Index.NO : 인덱싱을 하지 않는다. 고로 이렇게 저장한 값으로 검색을 할수 없다.
- Index.TOKENIZED : Analyzer에 의한 토크나이즈를 수행하여 인덱싱을 한다. 물론 검색 가능하다.
- Index.UN_TOKENIZED : 토크나이즈를 수행하지 않는다. 숫자라거나, 쪼갤필요가 없는 문자열에 사용하면 된다. 물론 검색이 되며, Analyze를 수행하지 않기때문에 인덱스 속도가 빠르다.
- Index.NO_NORMS : 이것은 인덱싱 시간이 매우 빨라야 할때 사용한다. Analyze를 수행하지 않는다. 또한 필드 Length 노멀라이즈를 수행하지 않는다. 인덱싱시에 적은 메모리만을 사용하게 된다는 장점이 있다.
1. 저장할 내용은 수필형식의 글이다. 해당 필드로 검색이 되어야 하며, 검색결과에서 바로 해당 글의 전문이 출력되어야 한다.
=> Store.YES, Index.TOKENIZED
2. 저장할 내용은 20070606 같은 형식을 가지는 띄어쓰기가 없는 날짜이다. 해당 필드로 검색이 되어야 하며, 검색어와 검색결과가 동일할테니 글의 내용을 저장할 필요는 없다.
=> Store.NO Index.Index.UN_TOKENIZED
3. 저장할 내용은 영화 제목과 영화 사용기이다. 영화 제목만으로 검색을 할 수 있으며, 사용기의 전문으로 검색은 되지 않는다. 하지만 검색결과에서 사용기가 출력되어야 한다.
=> 제목 Field : Store.YES, Index.TOKENIZED / 사용기 Field : Store.YES, Index.NO
분석
루씬에서 “분석한다”고 하면 사용자가 입력한 텍스트를 색인을 구성하는 가장 기본적인 형태인 “텀”으로 변환하는 과정을 의미한다.
루씬은 색인할때와 QueryParser 를 사용할 때 분석기를 사용한다.
| Analyzer analyzer = new StandardAnalyzer(); IndexWriter writer = new IndexWriter(directory, analyzer, true); |
위의 writer를 사용해 색인에 추가하는 모든 문서들 중에서 분석과정을 저장하도록 지정된 필드의 내용은 모두 analyzer 인스턴스를 통해 분석된다.
분석기 상세 분석
Analyzer 를 상속받아 새로운 분석기를 만들 때 꼭 작성해야 하는 메소드는 tokenStream() 이다.
| public TokenStream tokenStream(String fieldName, Reader reader); |
| Public final class SimpleAnalyer extends Analyzer public TokenStream tokenStream(String fieldName, Reader reader) { } |
Character.isLetter() 메소드를 이용해 문자열을 구분해서 글자를 뽑아내 모두 소문자로 변경하고, 글자가 아닌 숫자나 기호등은 무시한다.
Token 과 TokenStream
Tokenizer 와 TokenFilter는 모두 TokenStream을 상속받은 자식 클래스로서 input 값을 입력 받아 Token 단위로 다양한 처리를 한다.
tokenizer는 글자단위로 토큰을 만들어 내고,
TokenFilter는 토큰 단위로 처리한다. TokenStream이 토큰을 뽑아 내면 그 토큰에 새로운 토큰을 더하거나 삭제하고 변경할 수 있다.
![]()
루씬 API에 들어있는 분석기
| 클래스 | 목적 |
| TokenStream | Next() 와 close() 메소드를 정의하는 기본 클래스 |
| Tokenizer | Reader를 입력받는 TokenStream |
| CharTokenzier | 모든 글자 단위 |
| WhitespaceTokenzier | 공백 문자 |
| LetterTonkenzier | Character.isLetter() 가 true 인 경우 |
| LowerCaseTokenizer | 모든 문자를 소문자로 변경 |
| StandardTokenizer | 여러가지 문장요소 (이메일, 주소 등) 인식 |
| TokenFilter | TokenStream을 입력받는 TokenStream |
| LowerCaseFilter | 토큰의 단어를 소문자로 변경 |
| StopFilter | 불용어로 알려진 단어에 해당하는 토큰을 제거 |
| PorterStemFilter | 포터 스테밍 알고리즘에 따라 처리 (country 와 countries 모두 countri로 변경) |
| StandardFilter | StandardTokenizer의 결과 토큰을 처리. |
다음은 "AB&C 한글 aaa@gmail.com" 이라는 문장을 나온 각각의 Analzer로 인덱싱 한 결과이다.
a. WhitespaceAnalyzer : [AB&C] [한글] [aaa@gmail.com]
b. SimpleAnalyzer : [ab] [c] [com] [gmail] [한글] [aaa]
c. StopAnalyzer : [ab] [c] [com] [gmail] [한글] [aaa]
d. StandardAnalyzer : [ab&c] [aaa@gmail.com]
| public TokenStream tokenStream(String fieldName, Reader reader) { return new StopFilter( new LowerCaseTokenizer(reader), stopTable); |
위의 StopAnalyzer의 내부를 보면, LowerCaseTokenizer가 먼저 reader 변수에서 테스트를 읽고, 소문자로 변환된 토큰을 Stopfilter에 넘겨준다. LowerCaseTokenizer 에서 글자가 아닌 숫자나 기호 등은 이미 제건된다. 그 다음 StopFilter는 불용어 목록에 등록된 단어에 해당하는 토큰을 제거한다.
이와 같이 Tokenzier와 TokenFilter 몇 개를 연결하면 복잡한 분석기도 어렵지 않게 만들어 낼수 있다.
내장분석기 활용
루씬은 현재 기본적으로 7개의 분석기를 제공.
| 이름 | 작업내용 |
| WhitespaceAnalyzer | 공백을 기준으로 토큰을 분리한다. |
| SimpleAnalyzer | 문자가 아닌 숫자나 기호에서 토큰을 분리하고, 소문자로 변경한다. |
| StopAnalyzer | 문자가 아닌 숫자나 기호에서 토큰을 분리하고, 소문자로 변경하고, 불용어를 제거한다. |
| StandardAnalyzer | 이메일 주소, 약어, CJK 문자열, 알파벳과 숫자등을 인식해 토큰으로 분리하고, 소문자로 변경하고, 불요어를 제거한다. |
| CJKAnalyzer | |
| KoreanAnalyzer |
유니콘에서 lucene 사용 분석
참고 사이트 : http://www.conv2.com/blog/index.php?pl=370&ct1=3&ct2=36
lucene-core-2.0.0 사용
![]()
- FileDocument.java : 파일명을 기준으로 no, id, sort 을 추출한 후, 파일 내용을 FileReader로 읽어서 content로 한 다음, Document 객체를 만든다.
- IndexDTO.java : 색인 위한 DTO(Data Transfer Object).
- IndexEngine.java : 색인을 위한 메소드의 모음. - 초기화, 재구성, 최적화, 색인에 추가, 색인내 삭제
- SearchEngine.java : 검색을 위한 메소드의 모음.
- StoreDocument.java : 저장 위한 DTO(Data Transfer Object).
색인 시점
- WAS 로딩시 index의 initialize 수행
![]()
- 관리자 모드에서 재색인, 게시물/메모의 등록/수정/삭제시 색인
- indexing(ConnectionContext resource, String insertItems) – reoraganize 시
- indexing(String content, String key) – 이벤트가 발생했을 때
![]()
분석기
- 색인 할 때
![]()
- 검색 할 때
![]()
- 검색 메소드
- public Collection search(String queryString, String boardId)
- public Collection search(String queryString)
- 검색 : content 즉 본문(게시물/메모)에만 대응해서 검색.


