검색결과 리스트
2011/03/08에 해당되는 글 5건
- 2011.03.08 2011.03.08.Tues 아키텍처 발전역사
- 2011.03.08 su, sudo : 특정 사용자 권한으로 쉘/명령 실행
- 2011.03.08 바이트 오더링(byte ordering)
- 2011.03.08 루씬과 색인,검색 클래스 사용예(Java)
- 2011.03.08 색인과 검색 주요 클래스
글
2011.03.08.Tues 아키텍처 발전역사
1. standalone
하나의 컴퓨터에 (프로그램의) 절차와 데이터가 모두 존재한다.
2. 2-Tier
다수의 공유가 가능하게 되었지만, 다수의 사람들이 동일한 데이터에 접근하여 수정하여 되면, 데이터가 망가지게 된다.
그래서 DataBase를 관리하는 시스템인 DBMS(DataBase Management System)을 두어, 동시 사용자들간에도 데이터를 이상없이
(무결성) 다룰 수 있도록 한다. (Data+Base는 Data를 저장하고 있는 기지라는 의미를 갖는다. )
유지보수의 관점에서는 엄청난 비용이 드는 문제점이다. 문제의 원인은 변경의 대상이 되는 절차가 모두 클라이언트 내에
존재하기 때문이다. (비지니스 로직을 포함하는 이런형태의 클라이언트를 Fat 클라이언트라 한다.)
이 문제를 어떻게 해결하였을까? 다음 세대의 아키텍처를 알아보자.
3. 2-Tier + Procedure
Procedure 라고 하며, 대부분의 현대 DBMS 에 지원하고 있다. 클라이언트는 처리로직을 가지고 있지 않으며, 단지
Database에 접근하기 위한 인터페이스로서만 동작하게 되며 이런 형태를 Thin 클라이언트라 한다.
(초창기 데이터베이스 시장은 Informix가 선점하고 있었으나, Oracle 이 Procedure를 통해 시장 주도권을 장악할 수 있었다.)
절차와 데이터가 함께 있는 형태는 장점이자 시스템의 속도를 너무 느리게 하는 단점으로 작용하였다. 이 문제를 어떻게
어떻게 해결하였을까? 다음세대의 아키텍처를 알아보자.
4. 3-Tier
이후에는 다수의 AS 노드와 DataBase 노드를 클러스터링하여 병렬시스템으로 구축한 소위 N-Tier 아키텍처가 유지된다.
5. 아키텍처의 발전역사
지금까지 알아본 아키텍처의 발전역사를 전체흐름은 아래 그림과 같다.
(정반합이란 헤겔의 변증법을 도식화한 논리전개 방식의 하나)
분리하여 해결하였다. 하지만 공유의 문제는 해결했지만, 유지보수성 문제가 발생하였다. 해결책으로 분리된 절차를
데이터베이스의 Procedure 형태로 결합하여 해결하였다. 하지만, 인터넷의 등장과 수많은 사용자들의 발생으로 데이터와
절차의 결합은 다시 성능의 문제를 가져왔고, 절차를 AS(Application Server)로 분리하여 이 문제를 해결하였다.
이상과 같이 아키텍처의 역사를 절차와 데이터의 관점에서 정반합의 연속으로 바라보면 이해하기 쉬워진다.
컴퓨터의 신호전달 과정
(이진수를 사용한 정보전달의 시초)
통해 모니터로 전달이 된다. (모니터에선 다시 디지털로 변경하여 최종출력을 할것이다.)
HAL과 Driver
제어할 수 있는 정보를 알고 있어야 한다. 하지만 수많은 하드웨어 정보를 운영체제가 포함하기에는 정보량이 너무 많아지게
된다. 그래서 HAL이라는 추상화 계층을 두어 운영체제는 특정 하드웨어에 종속적이지 않는 명령으로 하드웨어와 통신하려
한다. 각 하드웨어 제조사들이 제공하는 HW 제어정보를 담은 Driver는 이 HAL 계층에 결합 되어 실제적으로 하드웨어를
제어하는 나머지 퍼즐조각으로서 기능한다. kenerl 입장에서는 HAL로 인해 어떤 하드웨어를 사용하는지 모르고도, 미리
정해진 표준화된 규칙을 통해 하드웨어를 제어할 수 있게된다.
정리하느냐에 따라 문제해결을 빨리 할 수도, 느리게 할 수도 있다. 즉 자료구조란 문제를 빨리 해결하기 위해 데이터를
정리하는 방법이라 할 수 있다. 데이터란 절차 안에서만 그 의미를 갖기 때문에 절차로서의 알고리즘과 데이터로서의
자료구조는 뗄수야 뗄수 없는 관계에 있다.
'방법론로그 > OOAD' 카테고리의 다른 글
| 방법론(methodology) (0) | 2011.04.12 |
|---|---|
| 2011.03.08.Tues 아키텍처 발전역사 (0) | 2011.03.08 |
| [OOAD] 요구사항 수집부터 분석까지 (0) | 2010.12.13 |
| [OOAD] 아키텍처, IA , 화면기준안, 스토리보드 (1) | 2010.12.13 |
설정
트랙백
댓글
글
su, sudo : 특정 사용자 권한으로 쉘/명령 실행
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 실행을 허용하면, 위 명령은 성공하게 된다.
'운영체제로그 > Linux' 카테고리의 다른 글
| 리눅스 자격증 (0) | 2011.04.09 |
|---|---|
| 리눅스 파일시스템 계층 표준(Filesystem Hierarchy Standard) (0) | 2011.03.09 |
| su, sudo : 특정 사용자 권한으로 쉘/명령 실행 (0) | 2011.03.08 |
| cURL (0) | 2011.02.18 |
| grub에서 디폴트 부팅 os 변경하기 (0) | 2011.02.16 |
| Bash 스크립트 (0) | 2011.01.20 |
설정
트랙백
댓글
글
바이트 오더링(byte ordering)
크게 Big endian과 Little endian 방식이 존재하며, Little Endian을 사용하는 대표적인 벤더가 인텔이며, Big endian을 사용하는
벤더가 AMD 이다. 이기종 간에 통신을 하는 네트워크 프로그래밍에서는 두 종단 간에 올바로 통신하기 위해서는 통일된
방식이 필요하게 되는데, 네트워크 바이트 오더 표준은 Big Endian 방식이다. 네트웍을 통한 데이터 전송은 Big Endian을 통해
전송하며, 데이터를 송수신 하는 곳에서는 각자의 플랫폼에 맞는 바이트 오더의 변환이 필요하게 된다. 물론 바이트 오더는
2바이트 이상의 프리미티브 타입에 적용되는 내용이다. 1바이트 단위의 문자열 데이터는 바이트 오더의 변경이 불필요하기
때문이다.
Big endian과 Little endian 간의 차이를 다음 그림을 통해 알아보자
다음은 위의 개념을 이용하여 공용체로 바이트 오더를 알아보는 간단한 프로그램이다.
#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;
}
'네트워크로그' 카테고리의 다른 글
| [FTP] (2) 클라이언트 구현하기 (0) | 2011.03.09 |
|---|---|
| [FTP] (1) FTP(File Transmission Protocol) 프로토콜 이해 (0) | 2011.03.09 |
| 바이트 오더링(byte ordering) (0) | 2011.03.08 |
| OAuth의 세부사항 (0) | 2011.01.01 |
| OAuth의 개념과 대략적인 흐름 (0) | 2010.12.31 |
설정
트랙백
댓글
글
루씬과 색인,검색 클래스 사용예(Java)
인덱싱 클래스 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
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는 원문이 출력되지 않는 걸 알수 잇다.
'검색엔진로그' 카테고리의 다른 글
| [Lucene] java.lang.OutOfMemoryError : Java heap space (0) | 2011.03.15 |
|---|---|
| 루씬과 색인,검색 클래스 사용예(Java) (0) | 2011.03.08 |
| 색인과 검색 주요 클래스 (0) | 2011.03.08 |
| 로봇 프로토콜 (0) | 2011.03.07 |
설정
트랙백
댓글
글
색인과 검색 주요 클래스
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 만을 가지고 있어서, 실제로 요청할 때 해당 도큐먼트를 디스크에서 로드해서 반환한다. |
'검색엔진로그' 카테고리의 다른 글
| [Lucene] java.lang.OutOfMemoryError : Java heap space (0) | 2011.03.15 |
|---|---|
| 루씬과 색인,검색 클래스 사용예(Java) (0) | 2011.03.08 |
| 색인과 검색 주요 클래스 (0) | 2011.03.08 |
| 로봇 프로토콜 (0) | 2011.03.07 |