2011.03.08.Tues 아키텍처 발전역사

방법론로그/OOAD 2011. 3. 8. 23:30




소프트웨어 아키텍처는 연결되는 노드(컴퓨터)의 구성,  그로 인한 데이터 보안성과 공유성, 그리고 
데이터와 (처리)절차의 관점에서 바라보면 그 흐름을 쉽게 이해할 수 있다. 이 점에 초점을 맞추어 아키텍처의
발전역사를 알아보자. 


1. standalone
가장 초기의 SW 아키텍처로  독립적인 머신 단일머신에서 동작하는 형태이다.  
하나의 컴퓨터에 (프로그램의) 절차와 데이터가 모두 존재한다.
 


단일머신에 데이터가 존재하기 때문에 보안적으로 안전하지만, 해당 PC 사용자만이 데이터를 사용할 수 있다. 
즉 데이터의 공유성이 좋지 않다.  공유성 문제를 해결하기 위해 2-Tier 아키텍처가 등장하게 된다. 



2.  2-Tier
절차를 가지는 노드와 데이터를 가지는 노드가 분리되어 네트웍으로 연결된 아키텍처이다.
다수의 공유가 가능하게 되었지만,  다수의 사람들이 동일한 데이터에 접근하여 수정하여 되면, 데이터가 망가지게 된다. 
그래서 DataBase를 관리하는 시스템인 DBMS(DataBase Management System)을 두어,  동시 사용자들간에도 데이터를 이상없이
(무결성) 다룰 수 있도록 한다.  (Data+Base는 Data를 저장하고 있는 기지라는 의미를 갖는다. )
 



공유성 문제는 해결이 되었지만,  처리절차의  변경 요구사항이 생겼을 때,  모든 클라이언트 모두를 업데이트 해주어야 한다. 
유지보수의 관점에서는 엄청난 비용이 드는 문제점이다. 문제의 원인은  변경의 대상이 되는  절차가 모두 클라이언트 내에 
존재하기 때문이다. (비지니스 로직을 포함하는 이런형태의 클라이언트를 Fat 클라이언트라 한다.)
이 문제를 어떻게 해결하였을까? 다음 세대의 아키텍처를 알아보자.  



3. 2-Tier + Procedure
처리절차(비지니스 로직)를 Database에  포함시키도록 하여 유지보수 문제를 해결하였다.  처리절차를 다루는 요소를 
Procedure 라고 하며,  대부분의 현대 DBMS 에 지원하고 있다.  클라이언트는 처리로직을 가지고 있지 않으며, 단지 
Database에 접근하기 위한 인터페이스로서만 동작하게 되며 이런 형태를 Thin 클라이언트라 한다. 
(초창기 데이터베이스 시장은 Informix가 선점하고 있었으나,  Oracle 이 Procedure를 통해 시장 주도권을 장악할 수 있었다.)


유지보수의 문제를 멋지게 해결해주었지만, 그에 따른 문제가 발생하였다. 인터넷의 등장 그리고  클라이언트 PC 의 급증으로
절차와 데이터가 함께 있는  형태는 장점이자 시스템의 속도를  너무 느리게 하는 단점으로 작용하였다.  이 문제를  어떻게 
어떻게 해결하였을까? 다음세대의 아키텍처를 알아보자.  




4. 3-Tier
결합되어 있는 처리절차를 다시 분리하여, 처리절차를 전담하는 AS(Application Server)에 할당하여 구성한 아키텍처 형태이다. 
이후에는 다수의 AS 노드와  DataBase 노드를  클러스터링하여 병렬시스템으로 구축한 소위 N-Tier 아키텍처가 유지된다. 





5. 아키텍처의 발전역사
지금까지 알아본 아키텍처의 발전역사를 전체흐름은 아래 그림과 같다. 



(처리)절차와 데이터의 관점으로 보았을 때,   아키텍처 발전의 역사는 정반합의 연속임을 알 수 있다.  
(정반합이란 헤겔의 변증법을 도식화한 논리전개 방식의 하나) 

절차와 데이터가 한데 모여 있었던 standalone에서는 데이터 공유문제를 해결하기 위해 데이터와 절차를 2-tier구조로 
분리하여 해결하였다. 하지만 공유의 문제는 해결했지만,  유지보수성 문제가 발생하였다.  해결책으로 분리된 절차를
데이터베이스의 Procedure 형태로 결합하여 해결하였다. 하지만, 인터넷의 등장과 수많은 사용자들의 발생으로  데이터와 
절차의 결합은 다시 성능의 문제를 가져왔고, 절차를 AS(Application Server)로 분리하여 이 문제를 해결하였다. 
이상과 같이 아키텍처의 역사를 절차와 데이터의 관점에서 정반합의 연속으로 바라보면 이해하기 쉬워진다. 













컴퓨터의 신호전달 과정 
그 옛날 정보전달을 위해 사용되었던 봉화 => 불꽃 연기의 피어오름의 유무를 통해 정보전달 하였다. 
이때 불꽃이 어디서 피어오르는지(불꽃의 위치), 불꽃의 개수, 불꽃의 순서가 중요한 의미를 가지게 된다.  
(이진수를 사용한 정보전달의 시초) 




컴퓨터 내외부에서 일어나는 모든 정보전달은 전기를 통해서 일어난다.  키보드 자판을 두드려서  일어난 신호는 
전선을 통해 컴퓨터에 전달이 되며, ADC(Analog Digital Converter)에 의해 디지털 신호로 변경된다.  이 데이터는 
메모리 공간에 저장이 되며, 두뇌가 되는 CPU에 의해 해석이 된다. 
출력은 CPU에 의해 출력정보가 메모리에 저장이 되며, 이 정보가 Driver를 통해 아날로그 신호로 변환되고,  다시 전선을
통해 모니터로 전달이 된다. (모니터에선 다시 디지털로 변경하여 최종출력을 할것이다.)

메모리에 대한 접근은 반드시 OS를 통해서 이루어진다. 사용자는 직접적으로 메모리에 접근할 수 없다. 



HAL과 Driver
Driver는 HAL(Hardware Abstract Layer)의 구현체이다. 동일한 운영체제가 다양한 머신에서 동작하기 위해서는 각각의 머신을
제어할 수 있는 정보를 알고 있어야 한다. 하지만 수많은 하드웨어 정보를 운영체제가 포함하기에는 정보량이 너무 많아지게
된다.  그래서 HAL이라는 추상화 계층을 두어 운영체제는 특정 하드웨어에 종속적이지 않는 명령으로 하드웨어와 통신하려
한다.  각 하드웨어 제조사들이 제공하는  HW 제어정보를 담은 Driver는 이  HAL 계층에 결합 되어 실제적으로 하드웨어를
제어하는 나머지 퍼즐조각으로서 기능한다.   kenerl 입장에서는 HAL로 인해  어떤 하드웨어를 사용하는지 모르고도, 미리
정해진 표준화된 규칙을 통해 하드웨어를 제어할 수 있게된다. 
ex) 누가 일을 하는지에 상관없이 일을 할수 있게된다. 




API(Application Programming Interface) 
무엇인가 컴퓨터의 기능을 사용하기 위해서는 반드시 OS를 거쳐야 한다. 그리고 기능들은 각각 일련의 절차들로
구성되어 있다.  OS의 기능을 사용할 수 있도록, 절차들을 묶어내어 제공하는 것이 API이다. 
ex) 일이 어떤  절차로 구성되어 있는지 상관없이 그 일을 할 수 있게된다. 

※ 추상과 인터페이스는 프로그래밍에서 중요한 의미를 갖는다. 추상과 인터페이스가 무엇이며, 이들이 어떻게 
다르며 어떤경우에 사용되는지를 잘 알아두자. 



알고리즘 vs  자료구조
알고리즘과 자료구조는 어떻게 다른가? 
알고리즘이란 문제를 해결하는 절차이다. 문제를 다루다 보면 데이터를 다루게 다루게 되며, 이 데이터를 어떻게 
정리하느냐에 따라 문제해결을 빨리 할 수도, 느리게 할 수도 있다. 즉 자료구조란 문제를 빨리 해결하기 위해 데이터를
정리하는 방법이라 할 수 있다. 데이터란 절차 안에서만 그 의미를 갖기 때문에 절차로서의 알고리즘과 데이터로서의
자료구조는 뗄수야 뗄수 없는 관계에 있다. 






su, sudo : 특정 사용자 권한으로 쉘/명령 실행

운영체제로그/Linux 2011. 3. 8. 18:10

 

su

su 는 substitue(교체하다)의 약자로  다른 사용자의 계정으로 전환해 주는 유틸리티이다. 

-,  -l, -login 모두 동일한 옵션으로, 이 옵션을 주고, 실행을 하면, 해당 사용자의 권한으로 쉘을 실행하고, 환경변수까지 변경해준다.  

su - hiddenviewer=> hiddenviewer 계정으로 쉘을 실행하고, 환경변수까지 변경함

 - 옵션을 사용하지 않고, su를 실행하면 해당 사용자의 계정으로 쉘을 실행하지만 환경변수는 변경하지 않는다. 

 

 

 

sudo

시스템 관리자나 다른 사용자의 권한으로 해당 명령을 실행할 수 있게 하는 명령으로,  이런 허용여부는 /etc/sudoers 파일에 설정되어 있다.  

일반 사용자 계정으로 로그인 했을 때, 잠시 관리자 권한으로 특정자원에 접근하고 싶을 때 sudo 명령을 사용하여 관리자 권한으로 

명령을 실행할 수 있다.  다른 사용자의 권한을 획득하려 할 때, 비밀번호를 묻게 되는데 이 비밀번호를 올바로 입력했다 하더라도, 

/etc/sudoers 파일에 해당 사용자가 지정되어 있지 않으면, sudo 명령은 실패하게 된다. 

 

sudo cat /etc/sudoers<= -u옵션으로 사용자를 지정하지 않으면, 기본으로 root로 실행함
Password:   <= 여기서 올바로 비밀번호를 입력했다 하더라도, /etc/sudoers에 hiddenviewer가 
명시되어 있지 않으면 실패한다.

 

 

/etc/sudoers 파일에

 hiddenviewer ALL=(ALL) ALL 
이라는 문장을 추가하여 sudo 실행을 허용하면, 위 명령은 성공하게 된다. 

바이트 오더링(byte ordering)

네트워크로그 2011. 3. 8. 15:04



바이트 오더는 데이터가 바이트 단위로 메모리에 저장되는 순서를 의미하며 각 CPU 벤더 의존적인 특징을 가지고 있다.
크게 Big endian과 Little   endian 방식이 존재하며,  Little Endian을 사용하는 대표적인 벤더가 인텔이며, Big endian을 사용하는
벤더가 AMD 이다.  이기종 간에 통신을 하는 네트워크 프로그래밍에서는  두 종단 간에 올바로 통신하기 위해서는 통일된
방식이 필요하게 되는데, 네트워크 바이트 오더 표준은 Big Endian 방식이다. 네트웍을 통한 데이터 전송은 Big Endian을 통해
전송하며, 데이터를 송수신 하는 곳에서는 각자의 플랫폼에 맞는 바이트 오더의 변환이 필요하게 된다.  물론 바이트 오더는
2바이트 이상의 프리미티브 타입에 적용되는 내용이다. 1바이트 단위의 문자열 데이터는 바이트 오더의 변경이 불필요하기
때문이다.



Big endian과 Little endian 간의 차이를 다음 그림을 통해 알아보자 

Big-endian은 가장 최상위 바이트(0A)가 가장 낮은 메모리 주소에 저장되는 방식이다.




Little-endian은 가장 최상위 바이트(0A)가 가장 높은 메모리 주소에 저장되는 방식이다. 




다음은 위의 개념을 이용하여 공용체로 바이트 오더를 알아보는 간단한 프로그램이다.  
 

#include <stdio.h>

int main(int argc, char **argv){    
    union {      
        short s;        
        char c[sizeof(short)];    
    } un;  

    un.s = 0x0102;      

    if (sizeof(short) == 2) {        
        if (un.c[0] == 1 && un.c[1] == 2)           
            printf("big-endian\n");        
        else if (un.c[0] == 2 && un.c[1] == 1)            
            printf("little-endian\n");       
        else            
            printf("unknown\n");   
    } else{      
            printf("sizeof(short) = %d\n", sizeof(short));   
    }   
    return 0;
}




루씬과 색인,검색 클래스 사용예(Java)

검색엔진로그 2011. 3. 8. 00:41


 

인덱싱 클래스 ATIndexer

인덱싱 데이터는 트위터에서 수집한 status 데이터를 별도 저장한 텍스트 파일을 사용하였으며, 

한건의 트윗글에 대해  status_id(글번호), text(내용), user_id(사용자번호), user_name(사용자이름)  

데이터만 사용하였다. 

루씬이 제공하는  필드에 따라 인덱싱하는 방법을 표현하기 각 데이터에 대해 다음과 같은 필드생성 옵션을 주었다. 

 

 

status_id : Field.UnStored 를 사용. 분석과 검색을 수행하지만, 저장되지 않기 때문에 검색결과에서 보여줄 수는 없음 

text : Field.Text 를 사용. 분석과 검색, 저장을 허용하여, 검색결과로 원문을 보여줄 수 있다. 
user_id : Field.UnIndexed 를 사용. 검색어로 사용할 수 없지만, 다른 필드의 검색결과에서 같이 보여질 수 있다. 

user_name : Field.Keyword 를 사용. 분석을 하지 않지만, 검색과 저장을 한다. 검색시 이 필드는 분석되면 않되기 

때문에 직접 텀쿼리를 만들어 IndexSearcher의 search 메소드에 전달해야한다. 

 

인데싱에 사용한 파일(crawled_text.data)의 포맷  

...

status_id:2147483648
text:@NicoleLapin so many buttons
user_id:12
user_name:Jack Dorsey

status_id:2147483648
text:In alaska for the longest day of the year with Delphine and eWee. Seaplanes. Sunshine.
user_id:14
user_name:noah glass

...

 

소스ATIndexer.java

      lucene-1.4.3.jar

       log4j-1.2.8.jar

  

package net.game.lucene.study;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.Hits;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.RangeQuery;
import org.apache.lucene.search.TermQuery;

// IndexSearcher
// Term
// Query
// TermQuery, RangeQuery, PrefixQuery, BooleanQuery, PharaseQuery, WildcardQuery, FuzzyQuery 
// Hits

public class ATSearcher {
        
        private String indexDir;
        private IndexSearcher indexSearcher;
        private Analyzer analyzer;
        
        private Logger log = Logger.getLogger(ATSearcher.class);
        
        public ATSearcher(String indexDir, Analyzer analyzer) throws IOException {
                BasicConfigurator.configure();
                
                this.indexDir = indexDir;
                this.analyzer = analyzer;
                this.indexSearcher = new IndexSearcher(this.indexDir);
        }
        
        public Hits search(String field, String searchWord) throws Exception {
                Hits hits;
                // user_name필드는 직접 텀쿼리를 생성하여 전달해야 올바른 검색결과를 얻을 수 있음 
                if (field.equals("user_name")) {
                        hits = this.indexSearcher.search(new TermQuery(new Term(field, searchWord)));
                } else {
                        Query query = QueryParser.parse(searchWord, field, this.analyzer);
                        hits = this.indexSearcher.search(query);
                }
                
                return hits;
        }
        
        public static void main(String[] args) throws Exception {
                BasicConfigurator.configure();
                
                ATSearcher searcher = new ATSearcher("/Users/hiddenviewer/index_lucene", new StandardAnalyzer());
                
                String line;
                BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
                
                System.out.println("<검색필드:검색어> 입력! (종료: quit)");
                
                while ((line = br.readLine()) !=  null) {
                        if (line.startsWith("quit")) {
                                System.out.println("ATIndexer Test 프로그램 종료!");
                                break;
                        } 
                        int delimIndex = line.indexOf(":");
                        if (delimIndex == -1) {
                                System.out.println("<검색필드:검색어> 포맷으로 입력해주세요");
                                continue;
                        }
                        
                        Hits hits = searcher.search(line.substring(0, delimIndex), line.substring(delimIndex+1));
                        
                        System.out.println("------------------------------------------");
                        System.out.format("검색결과 개수: %d \n", hits.length());
                        System.out.println("------------------------------------------");
                        
                        for (int i = 0; i < hits.length(); i++) {
                                Document d = hits.doc(i);
                                System.out.format("%20s: %s \n", "status_id", d.get("status_id"));
                                System.out.format("%20s: %s \n", "text", d.get("text"));
                                System.out.format("%20s: %s \n", "user_id", d.get("user_id"));
                                System.out.format("%20s: %s \n", "user_name", d.get("user_name"));
                        }
                }
                
        }
}

 


검색 클래스 ATSearcher

ATIndexer 가 인덱싱한 색인파일에서 검색을 하기 위해서 필드명:검색어 형태로 입력을 받는다. 필드명에 해당하는 필드에서

검색어가 포함된 도큐먼트를 찾아 검색결과를 출력해준다. 이때 중요한 것은 인덱싱 과정에서 Field.UnIndexed 로 지정한 user_id 필드는

검색어를 통해 검색할 수 없으며, 다른 필드를 통한 검색결과에만 포함되어 나온다. 또 Field.UnStored로 지정한 status_id 는 글번호로 검색은
가능하지만, 원문을 저장하고 있지 않기 때문에 결과에는 원문이 출력되지 않는다. Field.Keyword 로 지정한 user_name은 인덱싱과정에서

분석이 되지 않기 때문에, 검색과정에서도 분석기에 의해서 분석되면 안된다. 검색필드가 user_name 인 경우에는 텀쿼리를 직접생성하여

IndexSearcher의 search 메소드에 전달해줘야 올바른 결과를 얻을 수 있다.

 

 

소스 : ATSearcher.java

 

package net.game.lucene.study;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.Hits;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.RangeQuery;
import org.apache.lucene.search.TermQuery;

// IndexSearcher
// Term
// Query
// TermQuery, RangeQuery, PrefixQuery, BooleanQuery, PharaseQuery, WildcardQuery, FuzzyQuery 
// Hits

public class ATSearcher {
        
        private String indexDir;
        private IndexSearcher indexSearcher;
        private Analyzer analyzer;
        
        private Logger log = Logger.getLogger(ATSearcher.class);
        
        public ATSearcher(String indexDir, Analyzer analyzer) throws IOException {
                BasicConfigurator.configure();
                
                this.indexDir = indexDir;
                this.analyzer = analyzer;
                this.indexSearcher = new IndexSearcher(this.indexDir);
        }
        
        public Hits search(String field, String searchWord) throws Exception {
                Hits hits;
                // user_name필드는 직접 텀쿼리를 생성하여 전달해야 올바른 검색결과를 얻을 수 있음 
                if (field.equals("user_name")) {
                        hits = this.indexSearcher.search(new TermQuery(new Term(field, searchWord)));
                } else {
                        Query query = QueryParser.parse(searchWord, field, this.analyzer);
                        hits = this.indexSearcher.search(query);
                }
                
                return hits;
        }
        
        public static void main(String[] args) throws Exception {
                BasicConfigurator.configure();
                
                ATSearcher searcher = new ATSearcher("/Users/hiddenviewer/index_lucene", new StandardAnalyzer());
                
                String line;
                BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
                
                System.out.println("<검색필드:검색어> 입력! (종료: quit)");
                
                while ((line = br.readLine()) !=  null) {
                        if (line.startsWith("quit")) {
                                System.out.println("ATIndexer Test 프로그램 종료!");
                                break;
                        } 
                        int delimIndex = line.indexOf(":");
                        if (delimIndex == -1) {
                                System.out.println("<검색필드:검색어> 포맷으로 입력해주세요");
                                continue;
                        }
                        
                        Hits hits = searcher.search(line.substring(0, delimIndex), line.substring(delimIndex+1));
                        
                        System.out.println("------------------------------------------");
                        System.out.format("검색결과 개수: %d \n", hits.length());
                        System.out.println("------------------------------------------");
                        
                        for (int i = 0; i < hits.length(); i++) {
                                Document d = hits.doc(i);
                                System.out.format("%20s: %s \n", "status_id", d.get("status_id"));
                                System.out.format("%20s: %s \n", "text", d.get("text"));
                                System.out.format("%20s: %s \n", "user_id", d.get("user_id"));
                                System.out.format("%20s: %s \n", "user_name", d.get("user_name"));
                        }
                }
                
        }
}


ATSearcher 실행결과

결과를 보면 Field.UnStored로 지정된 필드 status_id는 원문이 출력되지 않는 걸 알수 잇다.






색인과 검색 주요 클래스

검색엔진로그 2011. 3. 8. 00:27


 Apache OpenSource Project인 Lucene 을 구성하는 색인과 검색과 관련된 주요 클래스를 알아보자. 

 

색인 주요 클래스

색인과정 중에 사용되는 주요 클래스는 다음과 같다. 

클래스 설명
IndexWriter 색인을 생성하고, 색인에 도큐먼트를 추가한다.
IndexReader 색인에서 도큐먼트를 삭제한다
Directory

색인의 저장소. 일반적으로 파일시스템 FSDirectory와 메모리 RAMDirectory가 있다. 루씬 샌드박스에서 제공하는

데이터베이스를 색인의 저장소로 사용하는 JDBCDirectory 도 있다. 

Analyzer

내용을 텀 단위로 분리하는 역할을 하며, 색인과 검색 단계에서 동일한 분석기가 적용되야 올바른 검색결과를 얻을 수 있다. 

Document

검색을 위한 정보 구성의 단위가 된다. 하나의 메일 메시지 또는 하나의 웹페이지가 도큐먼트가 될수 있으며, 비지니스 로직에

따라 변경된다.

Field

도큐먼트 내에서 정보를 검색하는 대상(카테고리)이다. 분석의 여부, 검색 가능여부, 저장하는지 여부에 따라 Keyword, UnIndexed, UnStored, Text 필드로 구분된다.  이러한 구분의 검색과 검색결과로 보여질 데이터의 항목들을 명확히 하여,

검색의 질과 효율을 높이기 위함이다.


색인은 양질의 검색결과를 얻을 수 있도록 하는 근본이 되는 과정이다.  도큐먼트는 색인과 검색과정에서 정보의 저장과 검색의 단위가 되기 때문에, 어떠한 데이터들을 하나의 도큐먼트로 구성할지가 중요한 요소가 된다. 

 

도규먼트를 구성하는 필드들은 다음과 같은 값들 일 수 있다. 

필드 분석 검색 저장 사용 용도
Field.Keyword X O O  변경되지 않는 고유정보 저장하기 위해 사용됨. 예) 파일의 경로, 메일번호, 게시물 번호 
Field.UnIndexed X X O  검색의 결과로 보여주기 위해서만 사용되는 정보. 예) 웹페이지 글의 상위 네번째줄까지  글....
Field.UnStored O O X  검색의 대상이 되지만, 화면에는 보여질 필요가 없는 정보. 예) 웹문서의 태그...
Field.Text O O

String(O)

Reader(X)

String  타입은 내용이 색인에 저장되고, Reader 타입은 내용이 색인에 저장되지 않는데,  Reader는

불필요하게 많은 데이터를 저장하여 효율을 저하시킬 수 있기때문에 저장하지 않는다.

 

 

검색 주요 클래스 

검색과정 중에 사용되는 주요 클래스는 다음과 같다. 

 

클래스 설명
IndexSearcher

 색인에서 검색어를 찾아 결과를 반환하는 클래스.  검색단계에서도 검색어를 분석하는데 Analyzer 가 사용된다.

  이때 색인단계와 검색단계에서 동일한 텀이 생성되게 하는 것은 루씬 라이브러리를 사용하는 개발자의 몫이다. 

Term  매칭이 되는 가장 최소단위의 단어이다. 색인과 검색과정에서 (필드이름, 단어) 의 쌍으로 구성된다. 
Query

 루씬엔진이 해석할 수 있도록  검색의 조건을 변환한 클래스이다.  TermQuery, RangeQuery, PrefixQuery 등 다양한 조건에

 해당하는 Query문이 존재한다.  개발자는 사용자에게 적절한 검색인터페이스를 제공하여,  올바른 Query 을 생성해야한다 

QueryParser  다양한 조건을 좀더 편리하게 문자열 조건문 형태로 입력받고, 이 문자열을 Query 서브클래스들의 조합으로 변환한다.  
Hits

 IndexSearcher 클래스의 search 메소드의 검색결과 매칭된 도큐먼트들을 가지고 있는 결과객체이다. 실제 문서의 내용이

아닌 문서에 대한 ID 만을 가지고 있어서, 실제로 요청할 때 해당 도큐먼트를 디스크에서 로드해서  반환한다.