Chap. 19 Special Topics - Oracle Text/Lucene

(ref: Marko Asplund, "Oracle Text를 이용한 전체 텍스트 검색 애플리케이션의 구현“, OTN, 2007. 4.)

Introduction

• Oracle's IR Solution

• 기능

- 구조형/비구조형 문서 검색 용도로 활용

- 불리언 연산자(and, or, not, near 등)의 조합 지원

- 고급기능: soundex 검색, fuzzy 검색, 결과 랭킹 등

- MS-Office/PDF를 포함하는 수백여 종의 file type 지원

• 용도

- e-Business, 문서/기록 관리, issue tracking system 등

⇒ text 정보는 DB 내에 구조적인 형태로 저장되거나, local file/Web에 비구조적인 형태로 저장됨

• Oracle Text API

- 포괄적인 SQL 기반 검색 API 제공

⇒ custom query 연산자, DDL syntax 확장, PL/SQL procedure, database view 등을 포함

- application 개발자는 API를 이용하여 indexing, query, security, presentation, S/W 설정 등의 control을 확보할 수 있음.

e.g., 상용 application의 경우

S/W 설정을 가능한 단순하게 유지하는 것이 관건

⇒ 기술 지원, 유지보수, 업그레이드 등

- document level authorization 기능 지원

- 관계형 데이터 및 비구조형 데이터에 대해 text가 혼합된 query를 사용

⇒ 단일 SQL 내에서 전체 text 검색과 승인 기능을 함께 사용

⇒ 결과 set을 분리하고 filtering을 적용하는 작업이 최소화

e.g., ECM (Enterprise Contents Mgmt) 시스템의 경우

① DB 외부의 file contents를 검색

② DB 내의 metadata를 검색

③ 결과를 승인

④ 서로 분리된 결과 set을 병합

- 프로그래밍 언어로부터 독립적

⇒ Java, Php application과 유연하게 연동

실습 #1:

• 개요: Issue Tracking System

⇒ 제1판, 제2판 등 발행판 추적관리 시스템

⇒ metadata와 첨부 file들로 구성

id	issue_id	path	ot_format
1 2 3 …	1 2 2 …	‘E:\temp\oracletext\found1.txt’ ‘E:\temp\oracletext\found2.doc’ ‘E:\temp\oracletext\notfound.txt’ …	- - ‘IGNORE’ …

1. 환경 설정

- grant CTXAPP role to a user 'hr'

- Log in 'SYSTEM' and execute an SQL

GRANT ctxapp TO hr;

2. Create a table 'files'

CREATE TABLE files (

id	NUMBER	PRIMARY KEY,

issue_id	NUMBER,

path	VARCHAR(255) UNIQUE,	// 절대 file 경로

ot_format	VARCHAR(6)	// format column 정보

);

INSERT INTO files VALUES (1, 1, 'E:\temp\oracletext\found1.txt', NULL);

INSERT INTO files VALUES (2, 2, 'E:\temp\oracletext\found2.doc', NULL);

INSERT INTO files VALUES (3, 2, 'E:\temp\oracletext\notfound.txt', 'IGNORE');

- ot_format의 값은 indexing 과정에서 Oracle Text에 의해 계산됨

e.g., NULL: file을 위한 filter가 자동으로 선택

IGNORE: file을 완전히 무시

3. Create a CONTEXT type index

- 조회 가능한 item들에 대한 index를 생성

- 여러 가지 index type들 지원

⇒ 대용량 문서에 대한 전체 text 검색을 위해서는 CONTEXT index가 가장 적합

CREATE INDEX file_index ON files(path)

INDEXTYPE IS ctxsys.context

PARAMETERS ('datastore ctxsys.file_datastore format column ot_format'

lexer english_lexer	stoplist ctxsys.default_stoplist);

- 윗 구문은 indexing process가 베이스 테이블에 저장된 경로 정보를 이용하여 파일 시스템에서 파일을 인출하고, 그 컨텐트에 대한 filtering, indexing을 수행하도록 지시.

- CONTEXT 인덱스는 대소문자를 구분하지 않으며, 정확한 단어(word) 단위 matching을 지원. 여기서 indexing process의 customizing 작업을 통해 접두어(prefix), 접미어(suffix) matching 등을 지원할 수 있음.

- Oracle Text indexing process는 pipeline을 모델로 하며 데이터 저장소에서 인출된 데이터 item은 일련의 변환과정을 거친 후에 index에 그 keyword가 추가됨.

- Indexing process는 여러 단계로 나뉘며, 각 단계에서 처리되는 entity는 application 개발자에 의해 설정이 가능함

1. 데이터 인출: 데이터 저장소(웹 페이지, 데이터베이스 LOB, local file 시스템 등)로부터 데이터가 인출되어 다음 단계의 처리를 위해 데이터 stream으로 전달

2. Filtering: 서로 다른 파일 포맷의 데이터를 일반 텍스트로 변환하기 위해 필터링 프로세스가 적용.

⇒ Indexing pipeline의 다른 컴포넌트들은 일반 텍스트 포맷만을 처리하며 원본 파일 포맷(Microsoft Word, Excel 등)에 대해 알지 못함.

3. Sectioning: sectioner가 원본 데이터 아이템의 구조에 대한 메타데이터를 추가.

4. Lexing: character stream이 아이템의 언어를 기준으로 단어(word)로 분할됨.

5. Indexing: keyword가 실제 인덱스에 추가됨.

- Filtering은 대부분의 경우 각 파일의 format을 명시하지 않은 상태에서도 올바르게 동작하지만, format 컬럼을 베이스 테이블에 포함시킴으로써 indexing process를 보다 정교하게 제어할 수 있다는 장점이 있음.

e.g., 예를 들어 format 컬럼을 이용하여 특정 파일 타입이 indexing되지 않도록 설정하는 것이 가능.

⇒ 이 옵션은 Oracle Text에서 파일 format 중 일부만을 지원하고자 하는 경우에 특히 유용.

4. Searching

- index가 생성되고 나면 user는 application에서 SQL을 이용한 검색이 가능

-	metadata 및 첨부 file 컨텐트에 대한 full-text 검색을 수행

- CONTAINS 연산자는 CONTEXT index 검색을 위해 사용.

#1: find the keyword 'login'

- #2: find the keyword 'tykim'

5. Metadata 검색

- metadata 테이블

CREATE TABLE issues (

id	NUMBER,

author	VARCHAR(80),

summary VARCHAR(120),

description CLOB,

ot_version VARCHAR(10) // The ot_version column is the index column,	which can be used to force reindexing for	certain documents. The table can be populated	with test data:

);

INSERT INTO issues VALUES (1, 'Jane', 'Text does not make tea',

'Oracle Text is unable to make morning tea', 1);

INSERT INTO issues VALUES (2, 'John', 'It comes in the wrong color',

'I want to have Text in pink', 1);

- 검색: 간단한 boolean 연산자 사용

SELECT id FROM issues

WHERE CONTAINS(ot_version, 'color AND pink', 1) > 0;

SELECT id FROM issues

WHERE CONTAINS(ot_version, 'jane OR john', 1) > 0;

- score() 연산자: ranking

SELECT score(1), title, genre

FROM songs

WHERE CONTAINS(title, 'mice', 1) > 0;

This query should return a single row:

SCORE(1)	TITLE	GENRE

------- -----------------------   -----

5       The Preble Mice Go Squeak	CHILD

⇒ SCORE() ranks search results by relevance and provides a numeric value in the result set.

⇒ allows to determine which values are the best matches to the search criteria. In this query, SCORE() is given a label of 1 (inside the parentheses) that corresponds to the matching CONTAINS() search. The last argument in the CONTAINS() clause has the 'same' label value, 1.

⇒ If there are multiple CONTAINS() operators, separate labels can be used with SCORE() and CONTAINS() to determine the relevance for each. The value provided as the label is irrelevant to the score.

- CONTAINS 연산자와 함께 아래의 연산자들을 사용하여 고급 기능들도 사용가능

fuzzy(): fuzzy matching

$: stemming

…

SELECT score(1), title, genre

FROM songs

WHERE CONTAINS(title, '$mice', 1) > 0;

This query now returns two rows:

SCORE(1)TITLE	GENRE

------- -----------------------   ---------------

5       My Mouse Won't Work Blues	COMPUTER ENGINEER

5       The Preble Mice Go Squeak	CHILD

⇒ Some words, although originating from the same root or 'stem', are not spelled similarly enough for a wildcard to be of any use. For example, a search for 'mice%' will NOT return 'mouse'.

⇒ If I know the root form of a word, all variants of that word can be matched

- 접두어/접미어 matching을 위해 CONTAINS query에 wildcard 문자(%)를 활용

6. Index의 유지 보수

- 베이스 테이블 데이터는 index에 의해 복제되므로, index와 데이터를 주기적으로 동기화하는 작업이 필요.

- index 유지 보수 procedure는 CTX_DDL PL/SQL 패키지에 포함.

e.g., 베이스 테이블의 변경 사항을 반영하여 index를 업데이트하는 예

EXECUTE ctx_ddl.sync_index('issue_index', '2M');

⇒ 동기화 프로시저는 index name과 작업에 사용되는 memory size를 입력 매개변수로 받아들임.

- DBMS에서 이 작업을 일정 간격으로 자동 실행하도록 설정하는 것도 가능

- 운영 체제 또는 다른 스케줄링 기능을 통해 동기화 작업을 실행할 수도 있음.

e.g., UNIX 시스템의 경우 아래와 같은 쉘 스크립트를 Cron 작업 스케줄링 시스템에 등록하여 동기화를 수행할 수 있음.

#!/bin/sh

export ORACLE_SID=orcl

export ORAENV_ASK=NO

source /usr/local/bin/oraenv

sqlplus ot1/ot1@XE > synch.log <<EOF

WHENEVER SQLERROR EXIT 5;

EXECUTE ctx_ddl.sync_index('issue_index', '2M');

EOF

- 그 밖에도 CTX_DDL 패키지에는 index 최적화, index 조각 모음, 데이터 폐기 등에 관련한 유용한 procedure들이 포함.

- 문제가 발생한 경우에는 CTX_USER_INDEX_ERROR view에서 indexing error를 추적할 수 있음.

- DBMS는 index 컬럼의 변경 결과를 기준으로 문서의 변경 여부를 추적.

⇒ 따라서 Oracle Text에서 특정 문서의 index를 재생성해야 하는 경우, 해당 로우의 index 컬럼을 아래와 같은 방법으로 업데이트할 수 있음.

UPDATE files SET path=path WHERE id = 4;

⇒ 위 구문을 실행하면 index가 동기화될 때 id가 4인 파일의 index가 업데이트됨.

Index Implementation

(ref: J. Zobel and A. Moffat, "Inverted Files for Text Search Engines“, ACM Computing Surveys, Vol.38, No.2, July 2006)

• Index

- A data structure that maps 'terms' to the 'documents' that contain them.

- How to 'implement' the index?

• Inverted file

- a collection of lists, one per term, recording the identifiers of the documents containing that term.

e.g., The 'Keeper' database contains 6 documents.

- Complete 'document-level' inverted file for the 'Keeper' database.

The entry for each term t is composed of the frequency ft and a list of pairs, each consisting of a document identifier d and a document frequency fd,t.

The Wd values as computed for the 'cosine' measure shown below.

Wq,t : 'query' vector

Wd,t : 'document' vector

Sq,d : cosine of the angle in n-dimensional space between Wq,t and Wd,t

• e.g., for the 'NewsWire' data,

- the total 'index' size would be approximately 435MB (megabytes)

⇒ around 40% of the size of the 'original' data

- 12MB for '400,000' words, pointers, and counts

- 1.6MB for '400,000' Wd values

- 280MB for '70,000,000' document identifiers (4 bytes each)

- 140MB for '70,000,000' document frequencies (2 bytes each)

- For the Web data, the total size is about 21GB (gigabytes)

⇒ just over 20% of the original text.

Lucene

(ref: O. Gospodnetic and E. Hacher, "Lucene in Action“, Manning Publications Co., 2005)

• Introduction

- 'Open source' Java 검색 Engine

- The Lucene web site: http://lucene.apache.org/

- Download a binary file and install at c:

• README file

- Lucene is a Java full-text search engine.

- Lucene is not a complete application, but rather a code library and API that can easily be used to add search capabilities to applications.

- FILES

lucene-core-XX.jar   The compiled lucene library.

lucene-demos-XX.jar   The compiled simple example code.

luceneweb.war  The compiled simple example Web Application.

contrib/*   Contributed code which extends and enhances Lucene, but is not part of the core library.  Of special note are the JAR files in the analyzers and snowball directory which contain various analyzers that people may find useful in place of the StandardAnalyzer.

docs/index.html   The contents of the Lucene website.

docs/api/index.html   The Javadoc Lucene API documentation.  This includes the core library, the demo, as well as all of the contrib modules.

src/java  The Lucene source code.

src/demo Some example code.

• Demo

- Located at C:\lucene-2.2.0\src\demo\org\apache\lucene\demo

1. Indexing: 'IndexFiles'

java -cp lucene-core-2.2.0.jar;lucene-demos-2.2.0.jar org.apache.lucene. demo.IndexFiles c:\lucene-2.2.0\docs

2. Searching: 'SearchFiles'

java -cp lucene-core-2.2.0.jar;lucene-demos-2.2.0.jar org.apache.lucene. demo.SearchFiles

Enter query: IndexSearcher AND QueryParser

• Web Demo

- Need to install the 'Tomcat' JSP container

• 실습 #1

- Java 환경변수 CLASSPATH 설정: ‘lucene-1.4.3.jar’를 ‘lucene-core-2.2.0.jar’ 앞에 위치시킴

- Compile and Execute: Indexer.java, Searcher.java

• Index Structure

e.g. Fractal, DNA : 논리적인 ‘구조’에 ‘정보’가 저장

- Index 저장 위치: file system e.g., C:\lucene-2.2.0\index

c.f., DBMS 저장

- Indexing

□Field '이름과 내용'으로 이루어진 Field class를 모아 ‘Document’ instance를 만듬

□Document instance는 IndexWriter.addDocument method를 통해 Index에 추가

index1 (2 fields: title/ISBN)

title	ISBN
Tao Te Ching The Pragmatic Programmer JUnit in Action …	0060812451 020161622x 1930110995 …

Document #2

- Searching

□IndexSearcher class에 Query instance를 넘겨서 Index에서 Document를 검색

□Query와 일치하는 Document의 목록은 Hits class로 표현

- 두 가지 형태: multi-file/compound file

• Multi-file 구조

- Index는 'segment의 집합'으로 구성

⇒ 하나의 segment는 여러 개의 file들로 구성

- 하나의 segment에 포함된 여러 개의 file들은 같은 이름을 가지며 확장자만 다름.

⇒ segment는 sub-index의 개념

Fig B.2

- Index에 하나 이상의 segment를 사용하면 현재의 index에 포함된 segment를 건드리지 않고 새로운 segment를 계속 만들어 document를 추가할 수 있음

⇒ 필요한 경우 주기적으로 index의 전체 segment를 최적화하면서 하나로 병합

- Incremental indexing (증분 색인)

□index에 document를 추가하는 경우 전체를 재색인할 필요가 없는 기능

□document의 insert/delete가 빈번한 경우

- file 구조

□'segments' file: 해당 index에 포함된 segment 이름들의 목록 저장

□'deletable' file: IndexReader.delete()로 삭제된 document들의 목록 저장

□'xxx.f1‘, …, ’xxx.fn' files: document에 사용된 각각의 field들 저장

- multi-file 생성 코드

⇒ Lucene은 default로 compound file index를 사용함

IndexWriter writer = new IndexWriter(indexDir, new StandardAnalyzer(), true);

writer.setUseCompoundFile(false);

- Index에서 사용하는 전체 file 개수

⇒ segment 개수/field 개수와 함께 증가

⇒ O/S에서 프로그램이 동시에 open할 수 있는 file 개수 한정되어 있음

• Compound file 구조

- multi-file 구조에서 사용하던 여러 개의 file을 .cfs file 안에 묶어둠.

• Lucene Inverted file 구조

- http://lucene.apache.org/java/docs/fileformats.pdf

Fig. B.3

- Field name (.fnm)

□document가 갖고 있는 모든 field name들 저장

□색인화/벡터화 여부 표시

□순서는 생성될 시에 결정 (알파벳 순서는 아님)

⇒ field 위치는 해당 field와 f[0-9]* 확장자를 갖는 file(정규화 file)을 연결하는데 필요한 값

- Term dictionary (.tis)

□segment에 있는 모든 term들을 ‘field값’으로 저장

⇒ 알파벳 순서로 정렬

□document frequency를 가짐

⇒ segment 내에서 이 term을 가지는 문서의 개수

□.tii file: RAM에 상주하면서 .tis file에 random access할 수 있는 .tis file의 cache 부분

- Term frequency (.frq)

□.tis file의 ‘각 term’이 들어있는 문서의 목록(문서 번호)과 frequency를 저장

□frequency는 검색결과의 관련성(relevance)들을 계산할 때 사용

- Term location (.prx)

□stopword들을 제외하여 token화 된 문서 내 각 term의 위치를 저장

e.g.,

Document ID = 5 (“Java Development with Ant”) 경우

“java development ant apache jakarta ant build tool junit java development erik hatcher steve loughran”

term 'junit'의 위치 값 = 9

- Luke: Lucene 'index browser' http://www.getopt.org/luke/