|
Elastic/Elasticsearch 2013. 2. 1. 13:41
other tips [How do i configure the routing]
"routing" : { "required" : true, "path" : "indexType.user_uniq_id" } [How do i configure the compression]
"store" : { "compress" : { "stored" : true, "tv" : true } } [How do i configure the customized analyzer]
"analysis" : { "analyzer" : { "kr_analyzer" : { "type" : "custom", "tokenizer" : "kr_tokenizer", "filter" : ["trim", "kr_filter", "kr_synonym"] }, "kr_analyzer" : { "type" : "custom", "tokenizer" : "kr_tokenizer", "filter" : ["trim", "kr_filter", "kr_synonym"] } }, "filter" : { "kr_synonym" : { "type" : "synonym", "synonyms_path" : "analysis/synonym.txt" } } } }
[How do i disable the _all field] You can add some parameter. like this : {"include_in_all" : false} [Fully Configurations] curl -XPUT 'http://localhost:9200/index0' -d '{ "settings" : { "number_of_shards" : 50, "number_of_replicas" : 1, "index" : { "refresh_interval" : "60s", "term_index_interval" : "1", "store" : { "compress" : { "stored" : true, "tv" : true } }, "analysis" : { "analyzer" : { "kr_analyzer" : { "type" : "custom", "tokenizer" : "kr_tokenizer", "filter" : ["trim", "kr_filter", "kr_synonym"] }, "kr_analyzer" : { "type" : "custom", "tokenizer" : "kr_tokenizer", "filter" : ["trim", "kr_filter", "kr_synonym"] } }, "filter" : { "kr_synonym" : { "type" : "synonym", "synonyms_path" : "analysis/synonym.txt" } } } }, "routing" : { "required" : true, "path" : "indexType.user_uniq_id" } }, "mappings" : { "indexType" : { "properties" : { "docid" : { "type" : "string", "store" : "yes", "index" : "not_analyzed", "include_in_all" : false }, "rm_seq" : { "type" : "long", "store" : "yes", "index" : "no", "include_in_all" : false }, "rm_join_seq" : { "type" : "long", "store" : "yes", "index" : "no", "include_in_all" : false }, "rm_title" : { "type" : "string", "store" : "yes", "index" : "analyzed", "term_vector" : "yes", "analyzer" : "kr_analyzer", "include_in_all" : false }, "user_uniq_id" : { "type" : "string", "store" : "yes", "index" : "not_analyzed", "include_in_all" : false }, "mb_nm" : { "type" : "string", "store" : "yes", "index" : "analyzed", "term_vector" : "yes", "analyzer" : "kr_analyzer", "include_in_all" : false }, "mb_count" : { "type" : "integer", "store" : "yes", "index" : "no", "include_in_all" : false }, "rm_ymdt" : { "type" : "date", "format" : "yyyyMMddHHmmss", "store" : "yes", "index" : "not_analyzed", "include_in_all" : false }, "data_size" : { "type" : "long", "store" : "yes", "index" : "no", "include_in_all" : false }, "msgs" : { "properties" : { "msg_seq" : { "type" : "long", "store" : "no", "index" : "no", "include_in_all" : false }, "msg" : { "type" : "string", "store" : "yes", "index" : "analyzed", "term_vector" : "yes", "analyzer" : "kr_analyzer", "include_in_all" : false }, "send_user_uniq_id" : { "type" : "string", "store" : "yes", "index" : "not_analyzed", "include_in_all" : false }, "send_user_nick_nm" : { "type" : "string", "store" : "yes", "index" : "not_analyzed", "term_vector" : "yes", "analyzer" : "kr_analyzer", "include_in_all" : false }, "recv_ymdt" : { "type" : "date", "format" : "yyyyMMddHHmmss", "store" : "yes", "index" : "not_analyzed", "include_in_all" : false }, "cfn_yn" : { "type" : "string", "store" : "no", "index" : "no", "include_in_all" : false }, "send_yn" : { "type" : "string", "store" : "yes", "index" : "not_analyzed", "include_in_all" : false }, "msg_type" : { "type" : "integer", "store" : "yes", "index" : "not_analyzed", "include_in_all" : false } } } } } } }'
Original article is http://helloworld.naver.com/helloworld/273788
NHN Business Platform 글로벌플래폼개발랩
이재익
elasticsearch는 Shay Banon이 Lucene을 바탕으로 개발한 분산 검색엔진입니다. 설치와 서버 확장이 매우 편리하기
때문에 개발하고 있는 시스템에 검색 기능이 필요하다면 elasticsearch를 적용하는 것을 권장하고 싶습니다. 분산 시스템이기 때문에 검색
대상 용량이 증가했을 때 대응하기가 무척 수월하다는 것이 장점입니다.
이 글에서는 참고 자료의 내용을 바탕으로 기본적인 elasticsearch의 설치와 사용법을 설명하고, 실제 서비스에 적용할 때 고려해야
할 사항을 정리했습니다.
elasticsearch의 특징
우선 관계형 데이터베이스에 익숙한 사람들을 위해 관계형 데이터베이스와 elasticsearch의 용어를 비교한 표를 참고 자료에서
인용했다.
표 1 관계형 데이터베이스와 elasticsearch 용어 비교
관계형 데이터베이스 |
elasticsearch |
Database |
Index |
Table |
Type |
Row |
Document |
Column |
Field |
Schema |
Mapping |
Index |
Everything is indexed |
SQL |
Query DSL |
JSON 기반의 스키마 없는 저장소
elasticsearch는 검색엔진이지만, NoSQL처럼 사용할 수 있다. 데이터 모델을 JSON으로 사용하고 있어서, 요청과 응답을 모두
JSON 문서로 주고받고 소스 저장도 JSON 형태로 저장한다. 스키마를 미리 정의하지 않아도, JSON 문서를 넘겨주면 자동으로 인덱싱한다.
숫자나 날짜 등의 타입은 자동으로 매핑한다.
Multi-tenancy
elasticsearch는 multit-enancy를 지원한다. 하나의 elasticsearch 서버에 여러 인덱스를 저장하고, 여러
인덱스의 데이터를 하나의 쿼리로 검색할 수 있다. <예제 1>의 경우 날짜별로 인덱스를 분리해 로그를 저장하고 있고, 검색 시에는
검색 범위에 있는 날짜의 인덱스를 하나의 쿼리로 요청하고 있다.
예제 1 Multi-tenency 예제 쿼리
# log-2012-12-26 인덱스에 로그 저장 curl -XPUT http://localhost:9200/log-2012-12-26/hadoop/1 -d '{ "projectName" : "hadoop", "logType": "hadoop-log", "logSource": "namenode", "logTime":"2012-12-26T14:12:12", "host": host1", "body": "org.apache.hadoop.hdfs.StateChange: DIR* NameSystem.completeFile" }'
# log-2012-12-27 인덱스에 로그 저장 curl -XPUT http://localhost:9200/log-2012-12-27/hadoop/1 -d '{ "projectName" : "hadoop", "logType": "hadoop-log", "logSource": "namenode", "logTime":"2012-12-27T02:02:02", "host": "host2", "body": "org.apache.hadoop.hdfs.server.namenode.FSNamesystem" }'
# log-2012-12-26, log-2012-12-27 인덱스에 한번에 검색 요청 curl -XGET http://localhost:9200/ log-2012-12-26, log-2012-12-27/_search
확장성과 유연성
elasticsearch는 확장성과 유연성이 매우 뛰어나다. 플러그인을 이용해 기능을 확장할 수 있다. 예를 들어 Thrift 플러그인이나
Jetty 플러그인을 사용하면 전송 프로토콜을 변경할 수 있다. 필수 플러그인이라고 할 수 있는 BigDesk나 Head를 설치하면
elasticsearh 모니터링 기능을 사용할 수 있게 된다. <예제 2>에서 보는 것처럼 동적으로 복제본 개수를 조정할 수도 있다.
다만 샤드 수는 인덱스별로 고정돼 있어 수정이 불가능하므로 노드 수와 향후 서버 확장을 고려해 초기에 적절한 수를 할당해야 한다.
예제 2 설정 변경 쿼리
$ curl -XPUT http://localhost:9200/log-2012-12-27/ -d '{ "settings" : { "number_of_shards" : 10, "number_of_replicas" : 1 } }'
분산 저장소
elasticsearch는 분산 검색엔진이다. 키에 따라 여러 샤드가 구성되는 방식으로 데이터를 분산한다. 인덱스는 각각의 샤드마다
구성된다. 각각의 샤드는 0개 이상의 복제본을 가진다. elasticsearch는 클러스터링을 지원하며 클러스터가 가동될 때 여러 노드 중
하나가 메타데이터 관리를 위한 마스터 노드로 선출된다. 마스터 노드가 다운되면 자동으로 클러스터 내의 다른 노드가 마스터가 된다. 노드 추가
또한 매우 간단하다. 같은 네트워크에 노드를 추가하는 경우 추가된 노드가 멀티캐스트를 이용해 자동으로 클러스터를 찾아 자신을 추가한다. 같은
네트워크를 이용하지 않을 경우 유니캐스트로 마스터 노드의 주소를 명시해 주어야 한다(참고 영상:http://youtu.be/l4ReamjCxHo).
설치하기
Quick Start
elasticsearch는 무설정 설치가 가능하다. <예제 3>에서 볼 수 있는 것 처럼 공식 홈페이지에서 파일을 내려 받아
압축을 해제하기만 하면 바로 실행해 볼 수 있다.
- 다운로드
$ wget http://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-0.20.4.tar.gz $ tar xvzf elasticsearch-0.20.4.tar.gz
- 서버 실행
예제 3 설치 및 실행 명령
$ bin/elasticsearch -f
플러그인 설치
elasticsearch는 플러그인을 통해 쉽게 기능을 확장할 수 있다. 관리 기능을 추가하거나 Lucene의 Analyzer를 변경하고
기본 전송 모듈을 Netty에서 Jetty로 변경하는 것도 가능하다. <예제 4>는 플러그인을 설치하기 위한 명령어다. <예제
4>의 첫 번째와 두 번째 줄에서 보이는 'head'와 'bigdesk'는 elasticsearch 모니터링을 위한 필수 플러그인이므로 꼭
설치해서 기능을 확인해 보도록 하자. 설치 후 http://localhost:9200/plugin/head/와 http://localhost:9200/plugin/bigdesk/로 접속하면 웹 브라우저를 이용해 상태를
확인해 볼 수 있다.
예제 4 플러그인 설치
bin/plugin -install Aconex/elasticsearch -head bin/plugin -install lukas-vlcek/bigdesk bin/plugin -install elasticsearch/elasticsearch-transport-thrift/1.4.0 bin/plugin -url https://oss-es-plugins.s3.amazonaws.com/elasticsearch-jetty/elasticsearch-jetty-0.20.1.zip -install elasticsearch-jetty-0.20.1
주요 설정
간단한 기능 테스트에는 설정 변경이 필요 없으나, 성능 테스트를 하거나 실서비스에 적용할 때에는 기본 설정에 대한 몇 가지 변경이
필요하다. <예제 5>를 참고하면 초기 설정 파일(elasticsearch.yml)에서 변경해야 할 설정 내용이 무엇인지 알 수
있다.
예제 5 주요 설정(config/elasticsearch.yml)
# 클러스터를 식별하기 위한 이름이므로 유일성과 의미를 가진 이름을 사용하자 cluster.name: es-cluster
# 노드 이름은 자동으로 생성되지만 호스트명과 같이 클러스터 내에서 식별 가능한 이름을 활용하는 것이 좋다. node.name: "es-node1"
# 기본값은 아래 두 값이 모두 true다. node.master는 노드가 마스터가 될 수 있지에 대한 설정이고, node.data는 데이터를 저장하는 노드인지에 대한 설정이다. 보통은 두 값을 true로 설정하면 되고, 클러스터의 규모가 큰 경우에는 3가지 종류의 노드를 구성하기 위해 이 값을 노드별로 조정해 설정한다. 자세한 사항은 토폴로지(topology) 설정에서 다시 설명하겠다. node.master: true node.data: true
# 샤드와 리플리카 수를 변경하는 설정이다. 아래 값은 기본값이다. index.number_of_shards: 5 index.number_of_replicas: 1
#JVM의 스왑을 방지하려면 아래 설정 값을 true로 한다. bootstrap.mlockall: true
# 클러스터 내의 각 노드의 상태 체크를 위한 타임아웃 값으로, 너무 작게 하면 노드가 클러스터에서 자주 이탈하는 문제가 발생할 수 있어 적절한 값을 설정한다. 기본값은 3초다. discovery.zen.ping.timeout: 10s
# 기본값은 멀티캐스트를 사용하지만, 실환경에서는 다른 클러스터와 노드가 섞이는 위험이 발생할 수 있으므로 유니캐스트를 사용하고 두 번째 설정 값에 마스터가 될 수 있는 서버들의 목록을 나열하는 것이 좋다. discovery.zen.ping.multicast.enabled: false discovery.zen.ping.unicast.hosts: ["host1", "host2:port", "host3[portX-portY]"]
REST API 사용하기
elasticsearch는 <예제 6>과 같은 형식의 REST API를 제공한다. 인덱스 생성과 삭제, 매핑 생성과 삭제,
검색, 설정 변경 등 대부분의 기능을 REST API를 통해 제공한다. REST API 이외에도 Java, Python, Ruby 등의 언어별
클라이언트도 제공하고 있다.
예제 6 REST API 형식
http://host:port/(index)/(type)/(action|id)
<예제 7>의 경우 날짜별로 인덱스를 분리하고, 프로젝트별로 타입을 나누어 관리하고 있다. 2012년 12월 27일에
hadoop이라는 프로젝트로 들어온 로그를 문서 단위로 생성하는 과정을 REST API를 사용해 수행하는 예다.
예제 7 REST API 사용 예
#문서 생성 curl -XPUT http://localhost:9200/log-2012-12-27/hadoop/1 curl -XGET http://localhost:9200/log-2012-12-27/hadoop/1 curl -XDELETE http://localhost:9200/log-2012-12-27/hadoop/1
#검색 curl -XGET http://localhost:9200/log-2012-12-27/hadoop/_search curl -XGET http://localhost:9200/log-2012-12-27/_search curl -XGET http://localhost:9200/_search
#인덱스 상태 보기 curl -XGET http://localhost:9200/log-2012-12-27/_status
문서와 인덱스 생성
<예제 8>에서처럼 요청을 보내면 인덱스와 타입이 정의돼 있지 않더라도 elasticsearch는 자동으로
log-2012-12-27 인덱스와 hadoop 타입을 생성한다. 자동으로 생성하지 않고 명시적으로 생성하려면 설정 파일에서
action.auto_create_index와 index.mapper.dynamic의 설정 값을 false로 명시해야 한다.
예제 8 문서 생성
# 요청 curl -XPUT http://localhost:9200/log-2012-12-27/hadoop/1 -d '{ "projectName" : "hadoop", "logType": "hadoop-log", "logSource": "namenode", "logTime":"2012-12-27T02:02:02", "host": "host2 ", "body": "org.apache.hadoop.hdfs.server.namenode.FSNamesystem" }'
# 결과 { "ok" : true, "_index" : "log-2012-12-27", "_type" : "hadoop", "_id" : "1", "_version" : 1 }
<예제 9>에서 보는 것처럼 타입을 문서에 포함해 요청할 수 있다.
예제 9 타입을 포함한 쿼리
curl -XPUT http://localhost:9200/log-2012-12-27/hadoop/1 -d '{ "hadoop" : { "projectName" : "hadoop", "logType": "hadoop-log", "logSource": "namenode", "logTime":"2012-12-27T02:02:02", "host": "host2 ", "body": "org.apache.hadoop.hdfs.server.namenode.FSNamesystem" } }'
<예제 10>과 같이 ID 값을 생략하면 자동으로 ID를 생성하고 문서를 만든다. 요청 시 PUT 대신 POST 방식을 사용한
것에 주의하자.
예제 10 ID 없는 문서 생성 쿼리
# 요청 curl -XPOST http://localhost:9200/log-2012-12-27/hadoop/ -d '{ "projectName" : "hadoop", "logType": "hadoop-log", "logSource": "namenode", "logTime":"2012-12-27T02:02:02", "host": "host2 ", "body": "org.apache.hadoop.hdfs.server.namenode.FSNamesystem" }'
# 결과 { "ok" : true, "_index" : "log-2012-12-27", "_type" : "hadoop", "_id" : "kgfrarduRk2bKhzrtR-zhQ", "_version" : 1 }
문서 삭제
<예제 11>은 문서를 삭제하는 방법을 보여 주고 있다. DELETE 메서드를 사용해 log-2012-12-27 인덱스에서
타입이 hadoop이고 ID가 1인 문서를 삭제한다.
예제 11 문서 삭제 쿼리
# 요청 $ curl -XDELETE 'http://localhost:9200/log-2012-12-27/hadoop/1'
# 결과 { "ok" : true, "_index" : "log-2012-12-27", "_type" : "hadoop", "_id" : "1", "found" : true }
문서 가져오기
<예제 12>와 같이 GET 메서드를 사용하면 log-2012-12-27 인덱스에서 타입이 hadoop이고 ID가 1인 문서를
가져올 수 있다.
예제 12 문서를 가져오기 위한 쿼리
#요청 curl -XGET 'http://localhost:9200/log-2012-12-27/hadoop/1'
# 결과 { "_index" : "log-2012-12-27", "_type" : "hadoop", "_id" : "1", "_source" : { "projectName" : "hadoop", "logType": "hadoop-log", "logSource": "namenode", "logTime":"2012-12-27T02:02:02", "host": "host2 ", "body": "org.apache.hadoop.hdfs.server.namenode.FSNamesystem" } }
검색
검색 API를 호출하면 elasticsearch는 검색 API를 실행한 후 질의 내용과 일치하는 검색 결과를 반환한다. <예제
13>에서 검색 API를 사용하는 예제를 볼 수 있다.
예제 13 검색 API 사용 예제 쿼리
# 특정 인덱스의 모든 타입 $ curl -XGET 'http://localhost:9200/log-2012-12-27/_search?q=host:host2'
# 특정 인덱스의 특정 타입 $ curl -XGET 'http://localhost:9200/log-2012-12-27/hadoop,apache/_search?q=host:host2'
# 모든 인덱스의 특정 타입 $ $ curl - XGET 'http://localhost:9200/_all/hadoop/_search?q=host:host2'
# 모든 인덱스와 타입 $ curl -XGET 'http://localhost:9200/_search?q=host:host2'
URI 요청을 사용한 검색 API
URI를 사용하면 <표 2>의 파라미터와 쿼리 스트링(Query String)으로 간단하게 검색할 수 있다. 모든 검색 옵션을
제공하지는 않으므로 주로 테스트 용도로 간편하게 사용할 때 유용하다.
표 2 주요 파라미터들
이름 |
설명 |
q |
쿼리 스트링 |
default_operator |
기본으로 사용할 연산자(AND 혹은 OR). 기본값은 OR. |
fields |
결과로 가져올 필드. 기본값은 '_source' 필드. |
sort |
정렬 방법(예: fieldName:asc/fieldName:desc) |
timeout |
검색 수행 타임아웃 값. 기본값은 무제한. |
size |
결과 값의 개수. 기본값은 10. |
예제 14 URI 요청을 사용한 검색 쿼리
# 요청 $ curl -XGET 'http://localhost:9200/log-2012-12-27/hadoop/_search?q=host:host2'
# 결과 { "_shards":{ "total" : 5, "successful" : 5, "failed" : 0 }, "hits":{ "total" : 1, "hits" : [ { "_index" : "log-2012-12-27", "_type" : "hadoop", "_id" : "1", "_source" : { "projectName" : "hadoop", "logType": "hadoop-log", "logSource": "namenode", "logTime":"2012-12-27T02:02:02", "host": "host2", "body": "org.apache.hadoop.hdfs.server.namenode.FSNamesystem" } } ] } }
요청 바디(Request Body)를 사용한 검색 API
HTTP 바디를 사용할 경우 Query DSL을 사용해서 검색한다. Query DSL은 내용이 방대하므로 공식 사이트의 가이드 문서(http://www.elasticsearch.org/guide/reference/query-dsl/)를
참고하도록 하자.
예제 15 Query DSL을 사용한 검색
# 요청 $ curl -XPOST 'http://localhost:9200/log-2012-12-27/hadoop/_search' -d '{ "query" : { "term" : { "host" : "host2" } } } '
# 결과 { "_shards":{ "total" : 5, "successful" : 5, "failed" : 0 }, "hits":{ "total" : 1, "hits" : [ { "_index" : "log-2012-12-27", "_type" : "hadoop", "_id" : "1", "_source" : { "projectName" : "hadoop", "logType": "hadoop-log", "logSource": "namenode", "logTime":"2012-12-27T02:02:02", "host": "host2", "body": "org.apache.hadoop.hdfs.server.namenode.FSNamesystem" } } ] } }
Mapping
Put Mapping API
특정 타입에 매핑을 추가하려면 <예제 16>과 같은 형태로 정의할 수 있다.
예제 16 매핑을 등록하기 위한 쿼리
$ curl -XPUT 'http://localhost:9200/log-2012-12-27/hadoop/_mapping' -d ' { "hadoop" : { "properties" : { "projectName" : {"type" : "string", "index" : "not_analyzed"}, "logType" : {"type" : "string", "index" : "not_analyzed"}, "logSource" : {"type" : "string", "index" : "not_analyzed"}, "logTime" : {"type" : "date"}, "host" : {"type" : "string", "index" : "not_analyzed"}, "body" : {"type" : "string"}, } } } '
Get Mapping API
정의한 매핑 정보를 얻기 위해서 <예제 17>과 같은 형태의 쿼리를 사용할 수 있다.
예제 17 매핑을 얻어오기 위한 쿼리
$ curl -XGET 'http://localhost:9200/log-2012-12-27/hadoop/_mapping'
Delete Mapping API
<예제 18>은 정의한 매핑을 삭제하는 예다.
예제 18 매핑을 삭제하기 위한 쿼리
$ curl -XDELETE 'http://localhost:9200/log-2012-12-27/hadoop'
성능 최적화 팁
메모리와 오픈 파일 수
검색할 데이터가 많아질수록 많은 메모리가 필요하다. elasticsearch를 운영하다 보면 메모리 사용으로 인한 문제를 많이 겪게 된다.
elasticsearch 커뮤니티에서 권장하는 운영 방법에 따르면, elasticsearch 전용 서버를 운영할 때는 메모리 용량의 절반만
elasticsearch에 할당하고, 나머지 메모리 용량은 운영체제가 시스템 캐시 목적으로 사용할 수 있도록 하는 것이 좋다. 메모리 크기는
ES_HEAP_SIZE 환경 변수를 설정하거나 JVM의 -Xms와 -Xmx 값을 사용해서 설정할 수 있다.
예제 19 힙 크기를 지정해 실행
bin/ElasticSearch -Xmx=2G -Xms=2G
elasticsearch를 사용할 때는 OOME(Out Of Memory Error)가 발생하는 경우가 많다. 필드 캐시가 최대 힙 크기를
넘어서면서 발생하는데, index.cache.field.type 설정을 기본값인 resident 대신 soft로 설정하면 soft 레퍼런스를
활용하므로 캐시 영역에 대해 우선 가비지 컬렉션(Garbage Collection)을 실행해 문제를 해결할 수 있다.
예제 20 필드 캐시 타입 설정
index.cache.field.type: soft
데이터가 많아지면 인덱스 파일 개수 또한 증가하게 된다. elasticsearch가 사용하고 있는 Lucene에서 인덱스를 세그먼트 단위로
관리하기 때문이다. 경우에 따라 MAX_OPEN 파일 개수를 넘어서는 일도 발생한다. ulimit 명령으로 최대 오픈 파일 제한을 변경해야
한다. 권장되는 값은 32000~64000이지만, 시스템 규모나 데이터의 양에 따라 더 큰 값으로 설정해야 할 수도 있다.
인덱스 최적화
날짜별로 인덱스를 관리하면 <예제 21>에서 보는 것처럼 관리가 필요 없는 오래된 로그를 쉽고 빠르게 삭제할 수 있어서,
문서별로 TTL 값을 설정해 삭제하는 것 보다 시스템에 주는 오버헤드가 적다.
예제 21 인덱스 삭제
$ curl -XDELETE 'http://localhost:9200/log-2012-10-01/'
인덱스 최적화(Index Optimization)를 수행하면 세그먼트를 병합시킨다. 이러한 방식으로 검색 성능을 향상시킬 수 있다. 다만
시스템에 부담을 주므로 시스템 사용이 적은 시간대에 작업하도록 해야 한다.
예제 22 인덱스 최적화
$ curl -XPOST 'http://localhost:9200/log-2012-10-01/_optimize'
샤드와 복제본
샤드 개수는 초기에 설정한 다음에는 변경이 불가능하므로 현재 시스템의 노드 수와 추후 발생할 수 있는 노드 증가를 고려해 정해야 한다.
예를 들어 현재 5개의 노드가 있고 향후 10개까지 노드를 증가시킬 계획이라면, 초기부터 샤드 수를 10개로 지정하는 것이 좋다. 초기에 5개로
지정하면 이후 노드를 10개로 증가시켜도 샤드는 5개이므로 5개의 노드는 활용할 수 없게 된다. 물론 복제본 수를 1로 지정했다면 추가한 5개
노드를 복제 전용 노드로 활용할 수 있다.
샤드 수를 늘리면 질의가 샤드 개수만큼 분산되므로 많은 데이터 처리에 유리하게 되지만, 너무 크게 설정하면 오히려 트래픽이 증가해 성능이
떨어질 수 있으니 적절하게 설정해야 한다.
클러스터 토폴로지 구성
elasticsearch의 설정 파일에는 <예제 23>과 같은 내용을 볼 수 있다. <예제 23>을 보면 세 가지
종류의 노드(데이터 노드, 마스터 노드, 검색 밸런서 노드)가 있음을 알 수 있다.
- 데이터 노드: 마스터 역할을 수행하지 않고, 데이터만 저장한다. 클라이언트로부터의 요청이 왔을 때 샤드에서 데이터를 검색하거나 인덱스를
생성한다.
- 마스터 노드: 클러스터를 유지하기 위한 역할을 하고 인덱싱이나 검색 요청을 데이터 노드들에 요청한다.
- 검색 로드 밸런서 노드: 검색 요청이 오면 노드들에 데이터를 요청 후 취합해 결과를 전달한다.
하나의 노드가 마스터와 데이터 노드 역할을 다 하도록 운영할 수도 있으나, 세 가지 형태의 노드를 각각 사용하면 데이터 노드의 부담을 줄일
수 있다. 또한 마스터 노드를 별도로 구성하면 클러스터의 안정성을 높일 수 있다. 게다가 마스터 노드와 검색 노드는 저사양의 서버 장비를 활용할
수 있도록 해 운영 비용 또한 줄일 수 있다.
예제 23 토폴로지 관련 설정 내용
# You can exploit these settings to design advanced cluster topologies. # # 1. You want this node to never become a master node, only to hold data. # This will be the "workhorse" of your cluster. # # node.master: false # node.data: true # # 2. You want this node to only serve as a master: to not store any data and # to have free resources. This will be the "coordinator" of your cluster. # # node.master: true # node.data: false # # 3. You want this node to be neither master nor data node, but # to act as a "search load balancer" (fetching data from nodes, # aggregating results, etc.) # # node.master: false # node.data: false
라우팅 설정
인덱싱할 데이터가 많으면 샤드의 수를 늘리는 것이 전체적인 성능을 증가시킬 수 있지만, 샤드의 개수를 증가시키는 만큼 노드 간의 트래픽이
증가한다는 문제점이 있다. 예를 들어 샤드가 100개면 하나의 검색 요청이 왔을 때 100개의 샤드에 모두 요청을 보내 데이터를 취합하는
형식이기 때문에 전체 클러스터에 부담이 된다. 라우팅을 사용하면 특정 샤드에만 데이터가 저장되어 샤드 수가 아무리 커져도 1개의 샤드에만 요청을
보내게 되므로 트래픽을 극적으로 줄일 수 있다. <그림 2>와 <그림 3>, <그림 4>는 Rafal Kuc이
Berlin Buzzwords 2012에서 발표한 자료에서 인용한 것이다. 라우팅을 사용하지 않으면 <그림 2>와 같이 전체 샤드에
모두 요청을 보내지만 라우팅을 사용하면 <그림 3>과 같이 특정 샤드에만 요청을 보내는 것을 볼 수 있다. <그림 4>에서
인용한 자료에 따르면 200개의 샤드에서 라우팅 사용 전과 후의 성능을 비교 했을 때 반응 시간이 10배 이상 차이 나는 것을 볼 수 있다.
라우팅을 적용하면 적용하지 않은 경우외 비교해 스레드 개수가 10~20배 증가하지만 CPU 사용률은 훨씬 적은 것을 볼 수 있다. 하지만 경우에
따라 라우팅을 적용하지 않은 것이 성능이 더 좋을 때도 있다. 여러 샤드로부터 결과가 취합되어야 하는 검색 질의에 대해서는 여러 샤드에 요청이
전달되는 것이 성능상 유리할 수 있다.
그림 2 라우팅 사용 전
그림 3 라우팅 사용 후
그림 4 라우팅 사용 전/후의 성능 비교
마무리
elasticsearch는 유용한 기능뿐만 아니라 간단한 설치와 높은 확장성때문에 사용자를 빠르게 늘려가고 있다. 버전 숫자로만 본다면
최근(2013년 1월 기준)에 0.20.4 버전이 나온 정도지만 커뮤니티가 활발하기 때문에 빠르게 기능이 개선되고 있다. 또한 점점 더 많은
회사에서 elasticsearch를 자사의 서비스에 사용하고 있다. 최근에는 개발자인 Shay Banon을 포함한 커미터들이 모여 Elasticsearch.com을 만들어 컨설팅과 교육을 제공하고
있다. 이번 글에서는 기본적인 설치와 사용 방법, 성능 튜닝을 위한 내용을 정리했다. 많은 개발자들에게 도움이 되길 바란다.
참고 자료
- NBP 글로벌플래폼개발랩 이재익
- 글로벌플랫폼개발랩에서 중국개발자들과 로그시스템을 개발하고 있다. 최근 elasticsearch, node.js, iOS 개발에 관심을
가지고 업무에 활용하고 있으며, 여가시간에는 무지함에서 벗어나기위해 독서를 하거나 여행을 하려고 노력 중이다.
Elastic/Elasticsearch 2013. 1. 24. 16:03
lucene kr analyzer 사용 시 lucene core 3.2 에서 3.6 으로 올리시게 되면 아래 클래스에서 빨갱이가 나옵니다. 아래는 수정한 코드 인데 뭐 보시면 너무나 기본이라 이런건 작성할 필요가 있는지도 ^^; 암튼 머리 나쁜 저는 필요 해서.. [KoreanAnalyzer.java] /** Builds an analyzer with the stop words from the given file. * @see WordlistLoader#getWordSet(File) */ public KoreanAnalyzer(Version matchVersion, File stopwords) throws IOException { this(matchVersion, WordlistLoader.getWordSet(new InputStreamReader(new FileInputStream(stopwords), DIC_ENCODING), matchVersion)); }
/** Builds an analyzer with the stop words from the given file. * @see WordlistLoader#getWordSet(File) */ public KoreanAnalyzer(Version matchVersion, File stopwords, String encoding) throws IOException { this(matchVersion, WordlistLoader.getWordSet(new InputStreamReader(new FileInputStream(stopwords), encoding), matchVersion)); } /** Builds an analyzer with the stop words from the given reader. * @see WordlistLoader#getWordSet(Reader) */ public KoreanAnalyzer(Version matchVersion, Reader stopwords) throws IOException { this(matchVersion, WordlistLoader.getWordSet(stopwords, matchVersion)); }
기존 KoreanAnalyzer 에는 Version argument 가 없어서 추가만 했습니다. :)
Elastic/Elasticsearch 2013. 1. 23. 19:02
퇴근 하면서 급하게 올리다 보니 아무런 내용도 없이 그냥 스크랩 내용만 등록을 했내요.
[요약하면] Term vectors are a mix between an
indexed field and a stored field. They’re similar to a stored field
because you can quickly retrieve all term vector fields for a given document:
term vectors are keyed first by document ID . But then, they’re keyed
secondarily by term, meaning they store a miniature inverted index for
that one document. Unlike a stored field, where the original
[어떤 경우에 사용하지] Sometimes when you index a document
you’d like to retrieve all its unique terms at search time. One
common use is to speed up highlighting the matched tokens in stored
fields. (Highlighting is covered more in sections 8.3 and 8.4.) Another
use is to enable a link, “Find similar documents,” that when
clicked runs a new search using the salient terms in an original document. Yet
another example is automatic categorization of documents. Section 5.9 shows
concrete examples of using term vectors once they’re in your index.
2.4.3 Field options for term vectors Sometimes when you index a
document you’d like to retrieve all its unique terms at search time. One common
use is to speed up highlighting the matched tokens in stored fields.
(Highlighting is covered more in sections 8.3 and 8.4.) Another use is to enable
a link, “Find similar documents,” that when clicked runs a new search using the
salient terms in an original document. Yet another example is automatic
categorization of documents. Section 5.9 shows concrete examples of using term
vectors once they’re in your index. But what exactly are term vectors? Term
vectors are a mix between an indexed field and a stored field. They’re similar
to a stored field because you can quickly retrieve all term vector fields for a
given document: term vectors are keyed first by document ID . But then, they’re
keyed secondarily by term, meaning they store a miniature inverted index for
that one document. Unlike a stored field, where the original String content
is stored verbatim, term vectors store the actual separate terms that were
produced by the analyzer, allowing you to retrieve all terms for each field, and
the frequency of their occurrence within the document, sorted in lexicographic
order. Because the tokens coming out of an analyzer also have position and
offset information (see section 4.2.1), you can choose separately whether these
details are also stored in your term vectors by passing these constants as the
fourth argument to the Field constructor: TermVector.YES —Records the unique
terms that occurred, and their counts, in each document, but doesn’t store any
positions or offsets information TermVector.WITH_POSITIONS —Records the
unique terms and their counts, and also the positions of each occurrence of
every term, but no offsets TermVector.WITH_OFFSETS —Records the unique terms
and their counts, with the offsets (start and end character position) of each
occurrence of every term, but no positions TermVector.WITH_POSITIONS_OFFSETS
—Stores unique terms and their counts, along with positions and offsets
TermVector.NO —Doesn’t store any term vector information Note that you
can’t index term vectors unless you’ve also turned on indexing for the field.
Stated more directly: if Index.NO is specified for a field, you must also
specify TermVector.NO .
We’re done with the detailed options to control
indexing, storing, and term vec-tors. Now let’s see how you can create a field
with values other than String .
Elastic/Elasticsearch 2013. 1. 23. 16:09
이런.. 아래 코드는 2.X 용이내요.. 3.X 에서는 동작 하지 않습니다. 그냥 새로 짜야겠내요.. ^^; -------------------------------------------------------------- Special Thanks to : 이창민 한글형태소 분석기 로컬 테스트.
http://cafe.naver.com/korlucene 카페에 보면
krmorph-20091117.war파일
한국어 형태소분석 파일을 테스트 해볼수 있는 파일을 개발자님이 직접 올려주셨네요. (공모전에
출품작이였던 것 같습니다.;)
첨부한 파일은 : 공모전에 출품하려고 개발자가 매뉴얼을 작성한 것 같습니다. 프로그램에 대해
자세하게 적혀있습니다.(카페에서 찾았습니다.)
krmorph-20091117.war
해당 파일을 실행시키는 방법
1. 이클립스에서 마우스 오른쪽 버튼 -> Import -> WAR file
2. 다운받은 krmorph-2091117.war파일 선택
3. 프로젝트 import 완료
4. 프로젝트 선택후 오른쪽 버튼 -> Run As -> Run On Server
(기존에 톰캣이 셋팅 되어 있어야 함. & 일반 웹프로젝트 톰캣셋팅과 동일함)
5. 톰캣 재시작
※ 접속 URL : http://localhost:8080/krmorph-20091117/
형태소 분석기 소스를 받아서 고치거나 사전 업데이트 후 실제 어떻게 동작 하는지 테스트 할때 사용하면 유용할 것 같내요. 어제 stopwords 잘 안되던거 테스트 하기 위해서 필요 했는데. ㅎㅎ 창민군 고마워요.. :)
Elastic/Elasticsearch 2013. 1. 23. 10:43
stopwords 적용을 하다 보니 그냥 심심해서 어떤 workflow 인지 올려봅니다. 뭐 소스 보시면 다 아시는 내용이라 그냥 혼자 저장용으로 활용... ^^
[기본 flow]
KoreanAnalyzer.java : 문장을 분석하기 위한 Analyzer 구성 (LUCENE.Version 과 stopwords, encoding)
KoreanTokenizer.java : 지정한 token type 별로 token 분리
KoreanFilter.java : 입력 받은 token 을 형태소 분석기를 이용해 AnalysisOutput 생성
MorphAnalyzer.java : 여기서 한국어의 형태소를 분석 (동사, 명사, 조사, 어간, 어미 등등 ) 하여 keyword 추출
[개념적 flow]
KoreanAnalyzer -> KoreanTokenizer -> KoreanFilter -> MorphAnalyzer
Elastic/Elasticsearch 2013. 1. 22. 18:56
lucene 튜토리얼(추천) 참조 사이트 : http://www.lucenetutorial.com/lucene-in-5-minutes.html
1. https://github.com/macluq/helloLucene에서 HelloLucene-mastsr.zip을
다운로드 받는다. 2. 압축을 해제 한다. 3. 마우스 오른쪽 버튼 -> import -> existing Maven
Projects 4. Maven install 5. /src/main/java/HelloLucene/HelloLucene.java
마우스 오른쪽 버튼 Run As > Java Application을 실행
lucene라이브러리를 사용하여 아래의 과정을 보여줌으로써 기본적인 개념을 잡을 수 있도록 도와줌 1. create the
index 2. query 3. search 4. display results
Elastic/Elasticsearch 2013. 1. 22. 18:55
Spacial Thanks to : 이창민. elasticsearch
한국어 형태소분석기 분석
- 소스 다운로드 (zip파일로 다운로드)
- 다운로드 : https://github.com/chanil1218/elasticsearch-analysis-korean
- 소스로 다운로드도 가능하지만 해당 위치를 elasticsearch plugin에서 플러그인명을
chanil1218/elasticsearch-analysis-korean로
지정할 경우에도 사용된다. 이 때, 해당
elasticsearch 버전이 최신버전이면 해당 플러그인을 찾지 못한다. 서버와 플러그인의 버전이 같아야 설치 가능
- 이클립스에 프로젝트 import 방법
- eclipsesearch-analysis-korean-master.zip파일을 압축해제한다.
- 이클립스->마우스 오른쪽 버튼-> Import-> Maven -> Existing Maven
Projects
- Browse...을 눌러 압축을 해제한 디렉토리를 선택하여 import 한다.
- 프로젝트 오른쪽 버튼 -> Run as -> Maven install을 하여 빌드 한다.
- 형태소 분석을 담당하는 주 클래스는 org.apache.lucene.analysis.kr.morph 패키지의 MorphAnalyzer
클래스이다.
KoreaTokenizer가 한글과 영문을 토큰 단위로 분리를 하면, 이중 한글만 (한글, 숫자+한글, 영자+한글)
MorphAnalyzer을 통해 형태소 분석.
- 형태소 분석한 결과는 KoreanFilter에 AnalysisOutput 클래스로 전달이 되며 명사인 경우만 색인어로 추출
- 형태소분석결과는 점수를 가진다. 30 or 100으로 표시되는 값
- 100인 경우는 형태소 분석에 성공한 경우이므로 분석결과를 그대로 색인어로 사용.
- 30인 경우는 문법형태소로는 분해를 하였지만 사전에는 없으므로 정확하지 않은 경우. 이런 경우는 검색이 않되는 경우를 방지하기 위해
bigram(바이어그램, 아래에 설명 추가)에
의해 추가로 색인어를 추출합니다.
- 예를 들면, "블로그에" 라는 어절이 있을 때 "블로그"가 사전에 등록되어 있지 않으므로 형태소분석결과는 "블로그에(N)"와
블로그(N), 에(J)"가 되지만 색인어는 "블로그에", "블로그", "블로", "로그", "그에"가 됩니다.
- 형태소 분석결과 사전이 없을 경우 바이어그램으로 색인어를 추출하는데 false drop된 문서가 나온는 단점이 있다.
- http://blog.daum.net/maxmin93/10990156 에서 절단 검색부분에 bigram의 문제점과
trigram이 좀더 나은 검색결과를 제공가능 하지만 장단점이 있는 것 확인.
- 위의 한국어 형태소 분석기에는 현재 분석결과가 사전에 없을 경우 bigram만 적용 됨.
- 사전 데이터는 org.apache.lucene.analysis.kr.dic 패키지에 존재한다. (사전데이터 각 파일 설명)
- total. dic : 기본사전
- 용언과 체언을 포함한 기본사전 입니다. 사전의 형식을 보면 다음과 같이 구성되어 있습니다.
==========================
납부,10011X
==========================
|
단어정보 - 단어정보는 6 글자로 구성되어 있는데 각 글자는 단어의 사용규칙을 나타내며 아래와 같습니다.
- 1 : 명사
- 2 : 동사
- 3 : 기타품사
- 4 : 하여동사
- 5 : 되어동사
- 6 : 불규칙변형
- 1 ~ 3 은 품사에 대한 정보이며, 위에 기술한 각 품사 여부를 나타냅니다.
- 4 ~ 5 는 명사인 경우 "하다" 와 "되다" 가 붙을 수 있는 경우를 나타냅니다. 주의) 동사는 반드시( 0 )이어야 합니다.
- 6 은 동사인 경우 불규칙변형의 종류를 나타내며 종류는 아래와 같습니다.
B: ㅂ 불규칙, H: ㅎ 불규칙, L: 르 불규칙, S: ㅅ 불규칙, R: 러 불규칙, X: 규칙
|
- extension.dic : 확장사전
- 기본사전은 가능한 그대로 사용하는 것이 좋음. 사전을 조금 보완하여야 할 때 확장사전을
사용하면 됨. 사전을 구성하는 기본 규칙은 기본사전과 동일
- josa.dic : 조사사전
- 조사들만 모아둔 사전. 각 조사는 한줄씩 구분이 됨
- eomi.dic : 어미사전
- 어미들만 모아둔 사전. 각 어미는 한줄씩 구분이 됨
- prefix.dic : 접두어 사전
- 복합명사를 분해시 2글자 이상의 단어로만 분해. 그러나 "과소비" 같은 경우 " 과"를
접두어로 분리해 내어 "과소비"와 "소비"를 색인어로 추출하기 위해 만든사전
- suffix.dic : 접미어 사전
- 복합명사를 분해시 "현관문" 같은 경우 "문"을 접미어로 분해하여 "현관문"과 "현관"을
색인어로 추출하기 위해 만든 사전
- compounds.dic : 기분석 복합명사 사전
- 복합명사는 명사 사전을 기반으로 최장일치법에 의해 분해를 합니다. 그러나
"근로자의날" 같은 경우 중간에 조사가 포함되어 있으므로 분해가 불가능합니다. 이런 경우 복합명사 사전에 등록을 합니다. 규칙은 다음과
같습니다.
==========================
근로자의날:근로자,날
==========================
|
- 콜론(\:)을 중심으로 좌측은 복합명사이고 우측은 함께 추출될 색인어입니다. 따라서 위의 경우는 색인어로 "근로자의날",
"근로자","날" 이렇게 3개가 추출됩니다.
- syllable.dic : 음절정보
- 현재 파악 중 (cj.dic , occurrence.dic, uncompounds.dic 3개의 파일)
|
N-gram이란? N-gram이란? N-gram은 텍스트나 문서에서 추출한 문자 또는 단어의 시퀀스이며, 문자
기반 및 단어 기반이라는 두 그룹으로 분류할 수 있다. N-gram은 단어 또는 문자열(이 튜토리얼의 경우)에서 추출한 N개의 연속 문자
세트이다. 이 방법의 배후에는 비슷한 단어가 N-gram의 높은 비율을 차지할 것이라는 개념이 깔려있다. 가장 일반적으로 사용되는 N값은 2와
3이며, 각각의 경우를 bigram과 trigram이라고 한다. 예를 들어, TIKA라는 단어에서는 T, TI, IK, KA, A*라는
bigram과 **T, *TI, TIK, IKA, KA, A*라는 trigram이 생성된다. ""는 채우기 공간을 의미한다.
문자 기반 N-gram은 문자열으 유사성을 측정하는데 사용된다. 문자 기반 N-gram을 사용하는 애플리케이션으로는 맞춤법 검사기
스테밍(strmming), OCR등이 있다. 발췌 : http://www.ibm.com/developerworks/kr/opensource/tutorials/os-apache-tika/section6.html |
Elastic/Elasticsearch 2013. 1. 22. 18:49
아주 기초가 되는 내용인데.. 웹에서 돌아 다니다가 발견해서 그냥 스크랩해 봅니다. 원본출처는 사이트가 없어진것 같고, 아래 링크에서 퍼왔내요. http://web.skhu.ac.kr/~mckim1/Lecture/IR/Note/hwork.html
Stopwords(불용어)
불용어란 검색엔진이 검색에서 무시해 버리는 문자열을 의미합니다. 전치사나 관사 a, an, the, that, this, in, on, by, if, is, are, as, be, but, of, for, to, from, with, you, he, there, may 등과 같이 의미없는 단어는 검색어로 취급되지 않는 것입니다. 검색식에 이러한 불용어나 특수기호(마침표,콤마,/,&,%,@,*,? ...)를 반드시 포함시키고자 한다면 대개는 구절검색 기능을 이용합니다. 어떤 검색도구에서는 불용어도 검색대상에 포함시킬 것인지에 대한 옵션을 제공하기도 합니다.
Any terms, Thesaurus Extended Derivatives 집단검색어,유의어,시소러스, 확장검색
예를 들어 검색을 '대도시'라고 썼을 때 전국의 대도시 지명들을 OR조건으로 모두 나열한 것과 같은 효과를 내는 검색방식입니다. 이것은 집단검색어 파일을 따로 갖고 있는 데이터베이스에서만 사용할 수 있습니다. 비슷한 기능으로서 유의어사전을 지원하는 검색도구들이 있습니다. 대표적인 것이 심마니입니다. 심마니에서는 예를 들어 '장애인#'이라고 검색식을 입력하면 장애인 뿐만 아니라 장애자, 장해인, 장해자 등도 찾아 줍니다. 이와 같이 사용자가 검색식에 입력한 문자열과 꼭 같지 않더라도 의미상 같거나 관련이 있는 용어들을 모아 검색가능하도록 구축한 데이터베이스를 시소러스(Thesaurus) 또는 유의어사전이라고 합니다. 약간 다르기는 하지만 주제어(Topic) 검색이라는 것이 있습니다. 영어성경검색이 좋은 예입니다. Poor라는 주제어를 입력하면, Beneficence; Giving; Liberality; Orphans; Poverty; Widow 등에 관하여도 볼 수 있습니다. 참고로 Lycos의 카탈로그나 야후의 디렉토리는 메뉴방식으로 원하는 정보를 선택하지만 사실은 내부적으로는 Topic별로 검색이 이루어지는 것입니다. 또 다른 하나의 예는 알파벳 순서에 의한 단어의 범위(Alphabetical Range of Words)를 지정하는 중괄호 { } (braces)입니다. Deja News에서 {monkey monkeying}라고 검색식을 입력하면 영어사전(엄밀히 말하면 Deja News의 색인집인 시소러스)의 monkey부터 monkeying까지 그 사이에 나오는 모든 단어가 검색대상이 됩니다. Extended Derivatives 영국의 웹검색기인 WWLib Extended Search Interface는 좀 특별한 확장검색을 합니다. 1.명사의 복수형도 검색하고 (Depluralisation) 2.동사의 분사형이나 진행형도 검색하며 (Degerundisation), 3.관련단어도 검색(Related words)해 주는 것이지요. 예를 들어 biology의 관련어에는 biologist, biologically 등이 있습니다.
Boolean Connectors 부울연산자 : 더하기, 빼기, 곱하기
1. AND 연산자 좌우의 검색어가 모두 나타나는 자료를 찾습니다. (예 welfare and rehabilitation) 주로 and나 플러스 기호(+)로 표시하지만, 연산자 없이 그냥 공백만으로 and연산을 하거나 그외 엠퍼센드 기호(&)를 쓰는 경우도 있습니다. 심마니에서는 '그리고/와/과/및' 등의 한글 연산자도 사용할 수 있습니다.
2. OR 연산자 좌우의 검색어 중 어느 하나만이라도(any word) 들어 있는 자료를 찾습니다. (예 aged or alzheimer) 주로 공백이나 or를 사용하지만, 가끔 플러스 기호(+)나 콤마(,)를 사용하기도 합니다. 검색도구에 따라서는 적합성(Relevancy) 점수를 부여할 때 or연산자 좌우의 단어가 모두 들어 있는 자료에 높은 점수를 주기도 합니다.
3. NOT 또는 AND NOT 연산자 앞쪽의 검색어를 포함하되, 뒤쪽의 검색어는 들어있지 않은 자료만 찾습니다. (예 retardation not illness) 주로 마이너스 기호(-)나 not를 많이 사용하지만, 느낌표(!)나 &!를 사용하기도 합니다.
Phrase Searching 구절검색
두개 이상의 단어가 순서대로 연속해서 나오는 것을 찾습니다. 예 "special education for the disabled children" 보통 구절을 따옴표(" ")로 싸 주는데, 검색엔진은 이 구절을 하나의 긴 문자열로 취급하는 것이지요. 주로 두 단어 이상으로 되어 있는 전문용어 등을 찾을 때 사용하지만, 검색 문자열에 특수기호(마침표,콤마,/,&,%,@,*,? ...)나 불용어까지 포함시키려는 경우에도 사용합니다.
※ 구절검색을 할 경우 절단검색 기호(*)는 사용할 수 없고 불용어가 아닌 단어를 두개 이상 포함해야 합니다.
Grouping by Parentheses 검색식의 문법
인터넷의 검색도구들에서도 대체로 여러개의 검색어와 연산자들을 결합하여 복잡한 검색식을 사용할 수 있습니다. 그러나 대개는 상용 데이터베이스와는 달리 and연산자가 or연산자보다 우선되는 것도 아니고 그저 검색식의 왼쪽으로부터 오른쪽으로 차례대로 연산하는데, AltaVista처럼 괄호를 사용하여 검색 연산순서를 바꿀 수 있는 것도 있습니다. 예를 들어, 검색식을 vocational and training or placement (알타비스타라면 +vocational +training placement라고 쓰겠죠.)라고 입력하면 vocational과 training이 동시에 들어 있거나, placement가 들어 있는 자료를 찾습니다. 앞에서부터 차례대로 연산하기 때문입니다. 만약 장애인의 직업훈련이나 직업알선(배치)에 관한 자료를 원한다면 vocational AND (training OR placement) 와 같이 우선 연산하고자 하는 부분을 괄호로 그룹지어야 합니다. 이와 같이 괄호로써 연산자의 조합을 조정할 수 없는 검색도구에서라면 AND조건이 필요한 검색어를 뒤로 보내어 training OR placement AND vocational와 같이 입력하는 것이 좋습니다. AltaVista라면 training placement +vocational 이렇게 입력해야겠지요.
Proximity Searching, Concatenation 인접연산자
인접연산자는 앞뒤의 검색어가 동시에 나와야 한다는 점에서 and연산과 비슷하지만 두 검색어가 바로 옆에 또는 일정 거리내에 인접하여 있어야 합니다. Welfare-Net,Korea와 같은 구조의 문자열을 찾으려면 주로 따옴표로 전체를 묶어 하나의 구절로 검색하는 것이 보통이지만 구절검색이 지원되지 않을 때에는 하이픈(-)이나 콤마(,) 등 특수기호나 불용어 자리에 인접연산자를 쓰면 좋습니다. ※ 앞뒤 검색어가 얼마나 가까이 붙어 있어야 하는가, 두 검색어 사이에 몇개까지의 단어가 끼어드는 것을 허용하는가 하는 인접정도는 검색도구에 따라 조금씩 다릅니다. 100단어 이내, 5글자 이내, 또는 한 문단내에 인접해 있는 조건으로 해석되기도 합니다. ※ 인접연산자는 보통 하나의 검색식 내에서 하나만 사용할 수 있습니다. 여러개의 인접연산자로 구성된 검색식은 거의 허용되지 않을 뿐 아니라 그렇게 써야 할 경우도 거의 없습니다. 또한 구절검색식과 인접연산자를 함께 사용할 수 없습니다.
검색어간의 순서까지 지정하는 ADJacent, 또는 Preceding 연산자 좌우의 검색어가 지정된 순서로 인접해 들어 있는 자료를 찾습니다. 다이얼로그의 Within 연산자와 같습니다.
예1 mental adj retardation Adj는 Adjacent(인접한)의 약자입니다. 예2 : attitude p3 disab* REHABDATA에서는 절단검색어는 인접연산자와 함께 사용할 수 있으나 구절검색어는 인접연산자와 함께 쓸 수 없습니다. 여기서 p는 preceding(앞에 오는)의 약자로 쓰였습니다.
검색어간의 인접관계만 지정하는 NEAR 이는 좌우 검색어가 앞뒤 순서에 관계없이 인접해 있는 경우를 말합니다. 다이얼로그의 Near 연산자와 같은 것이지요.
예1 : aged near/25 "day care" (WebCrawler) 예2 : welfare ^10 reform (Deja News) Deja News에서는 구절검색어나 절단검색어를 인접연산자와 함께 사용할 수 없습니다. 예3 : attitude w3 disab* (REHABDATA) REHABDATA에서는 절단검색어는 인접연산자와 함께 사용할 수 있으나 구절검색어는 인접연산자와 함께 쓸 수 없습니다. 여기서 w는 Within의 약자로 쓰였습니다. attitude for the disabled의 경우 w3을 써야 합니다. 즉, 인접연산기호와 함께 쓰이는 숫자에는 끝 단어도 계산되는 것입니다.
Truncation 절단검색
검색식에 입력된 문자열과 정확히 일치하는 단어를 찾아내는 것을 완전검색(Precise Searching)이라고 합니다. 검색도구에 따라 Whole words, Complete words, 똑같은거, Exact, Word based search 등으로 표현하는 옵션을 제공하기도 합니다. 예를 들어 입력된 용어가 'handicap'이면 정확히 handicap만 찾으므로, handicapped는 검색되지 않습니다. 검색식에 입력된 문자열로 시작하는 단어는 모두 검색해 준다든가 하는 기능을 절단검색이라고 합니다. 절단검색에는 검색어 뒷부분의 변화를 허용하는 우절단을 비롯하여 앞부분의 변형을 허용하는 후방일치 검색 등이 있습니다.
전방일치검색=어근검색=우절단검색 Right-Truncation 표현형식 : 단어* (또는 %단어) 절단검색 옵션을 선택하거나 검색어 뒤에 절단기호를 덧붙입니다. 절단기호(가변글자기호)로는 대부분 별표(*)를 사용하지만, 임의의 글자 수만큼 물음표를 사용하는 경우도 있습니다. 한편, 검색식에서는 절단기호(*)를 쓰지 않고 우절단검색, Word-stem based search, Substrings, Start with, 전방일치검색 등으로 표시한 옵션을 선택하게 되어 있는 검색시스템들도 많습니다. 단순히 절단검색이라고 하면 이 우절단검색을 의미한다고 보셔도 됩니다. 예 : disab* 용도 : 검색용어의 끝부분을 임의의 문자로 지정하는 것으로서, 영어의 경우에는 주로 단수형과 복수형(disability, disabilities / child, children)을 한꺼번에 검색하거나, 품사의 차이로 어미변화를 일으키는 용어(volunteer, volunteering, voluntary)를 검색할 때 사용하고, 우리말과 일본어의 경우 앞이 같은 말로 시작되는 유사어나 복합어(장애, 장애인, 장애인복지, 장애자, 장애인시설, 장애연금)를 검색하고자 할때 이용합니다.
후방일치 : Left-Truncation 표현형식 : *단어 (또는 단어%) 대부분 별표(*)를 사용하지만, 임의의 글자 수만큼 물음표를 사용하는 절단방식도 있습니다. 인터넷상의 거의 모든 검색도구들이 후방일치 절단검색을 지원하지 않습니다. 영국의 웹검색기인 WWLib Extended Search Interface에서는 이 기능을 지원합니다. 예 : 정보탐정에서 검색식을 '장애%'라고 쓰면 지체장애, 청각장애, 시각장애 등 '장애'로 끝나는 용어들을 찾아 줍니다. 용도 : 검색용어의 시작부분을 임의 문자열로 지정하는 것으로서, 영어단어의 경우 주로 화합물의 검색을 위해 사용한다고 하는데, 위의 예와 같이 이 검색식은 한글 복합어를 검색할 때 특히 유용합니다.
사이에 끼는 가변글자 표현형식 : 단어?단어 예 : wom?n 용도 : women, woman을 찾습니다. 다이얼로그와 같은 데이터베이스에서 주로 사용하는 것인데, 인터넷상의 정보검색엔진에서는 이런 검색방식을 지원하는 경우가 거의 없습니다. 다만 이와는 다르지만 영국의 웹검색기인 WWLib Extended Search Interface에서는 앞뒤로 절단검색하는 기능도 있습니다.
절단검색시 주의사항 절단검색어를 사용할 때, 어간이 짧은 경우에는 관계없는 용어들이 같이 검색되므로 어근을 너무 짧게 지정하지 않도록 주의하여야 합니다. 예를 들어, communication, communicate등 의사소통에 관한 자료를 찾기 위해 검색식을 com*이라고 쓰면 community, computer, compass, coma, commercial ...등 전혀 원하지 않는 용어들까지, 또는 너무 많은 용어들이 검색대상이 되어 버립니다.
Field (Context) Searching 필드 제한 검색
웹문서의 title, head, body, address 등이나 뉴스그룹 기사의 author, subject, newsgroup name 등 문서의 특정 부분(필드 또는 context라고 함)으로 제한하여 검색하면 보다 정확하고 빠르게 검색할 수 있습니다.
필드제한 검색의 유형 검색식에 직접 필드제한자를 붙이는 경우 가장 유연한 검색방식입니다. 고급 서처들에게는 검색식내에 직접 여러 연산기법들을 사용할 수 있게 하는 엔진이 좋은 법이지요. 예1 : AltaVista(예: title:"Department of Health and Human Services") 알타비스타의 필드제한 검색 특히, title, url, link필드에서의 검색은 정확한 자료를 찾아내는데 큰 도움이 됩니다. 그리고 이것은 과거에 책갈피를 만들어 둔 좋은 자료가 URL의 무단변경으로 인하여 더 이상 찾아내기 어려울 때 아주 유용한 검색기법입니다. 예를 들어 +url:sprc +title:"Social Policy Research Centre"의 검색은 지금의 정확한 주소는 모르지만 url과 타이틀중에 포함된 단어로써 찾아내는 것입니다. 나의 홈페이지,웹문서를 다른 곳들에서 얼마나 많이 링크시켜놓고 있는지를 알고 싶을 때 +link:http://welfare.or.kr -host:welfare.or.kr 이와 같이 검색식을 입력하면 됩니다. 예2 : Deja News(예: ~g alt.child*) 검색식을 입력한 다음 검색대상 필드를 옵션으로 선택하는 경우 예1 : Galaxy 예2 : OpenText Power Search 필드별 검색식 입력상자에 검색식을 작성하는 경우 예1 : REHABDATA 예2 : 유럽사회과학정보협의회 통합검색 CESSDA
필드내에서의 비교연산자 Comparison and Range Searches 필드검색에 있어서, 특히 위의 세번째 유형처럼 각 필드별로 검색식 입력상자가 따로 있는 경우는 좀더 진보된 고급 연산자를 지원하는 것도 있습니다.(예:REHABDATA) 인터넷상의 일반 검색엔진에서는 좀처럼 보기 어려운 연산자이기는 하지만 고급 문헌검색엔진(Dialog, BRS ...)이나 일반 DBMS(dBASEIII+, Approach...)에서는 다 지원되는 것입니다. 연산자기호
의미
예제 = Equal to (exact match) =access
> Greater than >5500
>= Greater than or equal to >=5500
< Less than <1-Jan-1996
<= Less than or equal to <=TX
: Within range 1993:1996
※ 주의사항 비교연산자는 수치의 대소뿐만 아니라, 문자열의 알파벳 순서(엄밀히 말하면 코드값), 날짜의 선후를 비교하는데에도 사용됩니다. Equal to 연산자(=)는 해당 필드내에 정확히 그 문자열만 들어 있어야 한다는 것입니다. 다른 단어(들)이 더 있어서도 안되는 것입니다. 이는 해당 필드내에 들어 있는 여러 단어 중 하나에 대하여 좌우 첨가없이 정확히 일치하는 Whole word(절단검색의 반대)를 찾는 것과는 또 다른 것입니다. 범위(range)연산기호 :대신에 ..등을 사용하기도 합니다. REHABDATA는 날짜필드에서 비교연산자와 함께 날짜값의 일부만 쓰는 경우, 즉 년월일을 다 적지 않고 년도나 월만 쓰는 경우에는 해당 년도 또는 월의 첫날부터 찾는 것으로 간주합니다. 그리고 날짜형식은 거의 모든 형식을 다 지원하지만 or연산자와 혼동될 수 있는 slash (/)는 쓰지 마십시오. 슬래시를 사용할 경우는 날짜 전체를 따옴표로 묶어야 합니다(예:"6/25/1996"). June 1995 또는 6-95와 같이 쓰시면 무난합니다.
Relevancy, Weight 적확도,정확성,우선순위
히트(hit) 검색결과 추출된 자료 또는 그 건수를 히트(hit)라고 합니다. 예를들어, 사용자가 입력한 검색식의 조건에 맞는 자료가 1,000건이 나왔을 경우 "1,000건이 hit되었다"라고 표현합니다. 이 경우 히트수는 1,000건이 되는 것이지요. 적합성(relevancy) 또는 우선순위(weight) 적합성이란 히트된 자료내에 우리가 요구한 검색어가 얼마나 중요한 곳에 들어 있는가? 또는 얼마나 많이 그리고 얼마나 여러번 나오는가? 등을 기준으로 계산하는 정확성의 척도입니다. 예를 들어 웹문서의 타이틀이나 헤드 영역에 해당 단어가 들어 있거나 자료 중에 우리가 입력한 검색식에 딱 맞는 문자열(들)이 들어 있거나 같은 검색어라도 문장 중에 여러번 나온다면 우리가 원하는 자료일 가능성이 높다는 뜻이 된다는 것입니다. 정확도를 평가하는 기준은 검색엔진에 따라 조금씩 다릅니다. 몇가지만 예를 들어 봅시다.
라이코스는 입력된 검색어들간의 인접정도와 출현빈도에 따라 적합성의 점수를 매깁니다. loose match는 적합성점수가 0.1이상인 자료를 찾아주고, 가장 높은 strong match는 0.9이상인 자료만 보여줍니다. 검색결과수(hit)나 적합성의 차이도 있지만 검색소요시간도 크게 차이나는데, strong match를 선택하면 아주 빨리 결과를 보실 수 있습니다. 마젤란은, 검색식에 입력된 검색어들 중에 몇개나 맞추는가와 출현횟수, 검색어가 웹문서의 Title(넷스케이프의 제목막대에 표시되는 문자열)이나 URL 또는 마젤란의 Review에 들어 있는가 를 기준으로 적합성의 점수를 부여합니다. 그리고 검색결과는 이 적합성이 높은 자료부터 표시됩니다. 기타 알타비스타나, 심마니, 미국 정부기록,간행물 데이터베이스 등의 경우도 비슷한 방법으로 정확성을 계산하고 결과에 그 값을 표시하되, 대개는 바로 이 적합성의 점수 순으로 정렬하여 보여줍니다. 적합성과 혼동되기 쉬운 것으로, 소위 사이트의 점수 (Rating)가 있습니다. 예를 들어, 마젤란 경우, 각 사이트를 평가하여 사용의 용이성, 갱신주기, 편집기술, 흥미유발정도 등을 기준으로 점수를 부여하고 그 결과를 별표(one to four stars)로 표시하는데, 별표가 많으면 점수가 높은 것입니다. 그러나 이 점수가 우리가 찾고자 하는 검색식에 얼마나 적합한가를 의미하지는 않습니다. 단지 그 사이트가 일반적으로 좋은 곳이냐 하는 것을 의미할 뿐입니다. 개별 자료의 정확도와는 전혀 다른 의미의 점수인 것입니다.
Elastic/Elasticsearch 2013. 1. 22. 14:25
원본출처 : http://cafe.naver.com/korlucene
형태소사전은 모두 8개로 구성되어 있습니다. 그 중 하나는 음절정보이므로 실제로는 7개로 봐야 하겠군요. 사전은 org/apache/lucene/analysis/kr/dic 아래에 있습니다. 이 사전은 모두 jar 에 함께 패키징되어 있는데, KoreanAnalyzer 는 우선 classpath 에 있는 파일에서 찾고 없으면 jar 에 패키징되어 있는 것을 읽어 옵니다. 따라서 커스터마이징된 사전을 사용하고자 한다면 %CLASSPATH%/org/apache/lucene/analysis/kr/dic 아래에 각자의 사전을 저장해서 사용하면 됩니다. 각 사전에 대한 자세한 설명은 다음과 같습니다. 1. total.dic : 기본사전 용언과 체언을 포함한 기본사전입니다. 사전의 형식을 보면 다음과 같이 구성되어 있습니다. ================ 납부,10011X ================ 콤마(,)를 중심으로 좌측은 단어이고 우측은 단어정보입니다. 단어정보는 6글자로 구성되어 있는데 각 글자는 단어의 사용규칙을 나타내며 아래와 같습니다. ========================================================= 1 2 3 4 5 6 명사 동사 기타품사 하여동사 되어동사 불규칙변형 ========================================================= 1~3은 품사에 대한 정보이며, 위에 기술한 각 품사 여부를 나타냅니다. 4~5는 명사인 경우 "하다"와 "되다"가 붙을 수 있는 경우를 나타납내다. 주의)동사는 반드시(0)이어야 합니다. 6은 동사인 경우 불규칙변형의 종류를 나타내며 종류는 아래와 같습니다. B:ㅂ 불규칙, H:ㅎ 불규칙, L:르 불규칙, U:ㄹ 불규칙, S:ㅅ 불규칙, D:ㄷ 불규칙, R:러 불규칙, X:규칙 2. extension.dic : 확장사전 기본사전은 가능한 그 대로 사용하는 것이 좋을 것입니다. 그런데 사전을 조금 보완하여야 할때 확장사전을 사용하면 됩니다. 사전을 구성하는 규칙은 기본사전과 동일합니다. 3. josa.dic : 조사사전 조사들만 모아둔 사전입니다. 각 조사는 한줄씩 구분되어 있습니다. 4. eomi.dic : 어미사전 어미들만 모아둔 사전입니다. 각 어미는 한줄씩 구분되어 있습니다. 5. prefix.dic : 접두어 사전 복합명사를 분해시 2글자 이상의 단어로만 분해합니다. 그러나 "과소비" 같은 경우 "과"를 접두어로 분리해 내어 "과소비"와 "소비"를 색인어로 추출하기 위해 만든 사전입니다. 6. suffix.dic : 접미어 사전 복합명사를 분해 시 "현관문" 같은 경우 "문"을 접미어로 분해하여 "현관문"과 "현관"을 색인어로 추출하기 위해 만든사전입니다. 7. compounds.dic : 기분석 복합명사 사전 복합명사는 명사 사전을 기반으로 최장일치법에 의해 분해를 합니다. 그런데 "근로자의날" 같은 경우 중간에 조사가 포함되어 있으므로 분해가 불가능합니다. 이런 경우 복합명사 사전에 등록을 합니다. 규칙은 아래와 같습니다. ========================================= 근로자의날:근로자,날 ========================================= 콜론(:)을 중심으로 좌측은 복합명사이고 우측은 함께 추출될 색인어입니다. 따라서 위의 경우는 색인어로 "근로자의날","근로자","날" 이렇게 3개가 추출됩니다.
Elastic/Elasticsearch 2013. 1. 22. 11:27
정말 오랜만에 보내요.. 제가 야후에 있을때 봤던 것 같은데.. 국민대 강승식 교수님의 한국어 형태소 분석기...
[한글 Stopword] https://github.com/wonderino/KeywordElection2012/blob/master/hdic/stopword.dic ; ;====================[ 불용어 및 특수색인어 사전 ]====================== ; ; 불용어(stopword)는 자동색인시에 색인어로 추출되지 않도록 하고 싶은 ; 명사들입니다. 즉, 이 파일에 등록된 stopword들은 색인어로 ; 출력되지 않습니다. ; ; 특수색인어는 자동색인시에 1 음절 명사 혹은 숫자로 시작되는 ; 용어가 누락되는 것을 방지하기 위한 것으로 특수색인어로 등록되면 ; 항상 색인어로 추출해 줍니다. ; ; ; *. 이 파일은 반드시 KS 완성형(KS C 5601-1987) 한글코드로 작성되어야 합니다. ; ; 2. line의 첫문자가 ';'이면 comment로 간주하여 무시됩니다. ; ; 3. line의 첫문자가 '_'이면 불용어로서 색인어로 출력되지 않습니다. ; ; 4. line의 첫문자가 '*'이면 특수색인어로서 항상 색인어로 출력됩니다. ; 1 음절 명사(예: 꽃, 핵)나 숫자로 시작되는 용어(예: 3.1절) 등 ; default로 불용어로 간주되는 용어가 누락되지 않게 할 때 사용합니다. ; ; 5. 색인어로 추출되지 않는 한글 명사를 특수색인어로 등록해도 ; 여전히 누락되는 경우가 있습니다. 이러한 용어는 특수색인어로 ; 등록하지 말고 사용자 정의사전(hangul.usr)에 등록하면 됩니다. ; ; 6. 한 line에 하나의 단어(명사)만 허용되며, line 중간에 blank 문자를 ; 허용하지 않습니다. ; ; 7. Text editor로 삽입/삭제할 때 반드시 sorting 순서를 지켜야 합니다. ; sorting 순서가 틀리면 실행할 때 error message를 출력합니다. ; ; 8. 이 사전에 수록될 수 있는 최대 단어수는 10,000단어까지이며, ; 또한 총 60,000bytes를 넘지 않아야 합니다. comment는 제외함. ; ; ; 국민대학교 컴퓨터학부 강승식 ;--------------------------------------------------------------------- ;--.|_ / /| Seung-Shik Kang Tel: (+82-2) 910-4800 ; / | /\ /\| Kookmin University Fax: (+82-2) 910-4868 ; ---- -+ School of Computer Science sskang@cs.kookmin.ac.kr ; () () | Songbuk-gu, Seoul 136-702, KOREA http://nlp.kookmin.ac.kr ;--------------------------------------------------------------------- ; *112 *114 *119 *12-12 *12-12사태 *12.12 *12.12사태 *128메가 *16메가 *1기가 *2000 *2002 *256메가 *3-1절 *3.1절 *386 *386PC *4-19 *4-19혁명 *4.19 *4.19혁명 *486 *486PC *4메가 *5-16 *5-16혁명 *5.16 *5.16혁명 *5.17 *5.18 *586 *586PC *6.25 *6.25사변 *64메가 *911 *D램 ;1IBM연구소 *S램 _a _about _above _across _after _against _all _almost _alone _along _already _also _although _always _among _an _and _another _any _anybody _anyone _anything _anywhere _are _area _areas _around _as _ask _asked _asking _asks _at _away _b _back _backed _backing _backs _be _became _because _become _becomes _been _before _began _behind _being _beings _best _better _between _big _both _but _by _c _came _can _cannot _case _cases _certain _certainly _clear _clearly _come _could _d _did _differ _different _differently _do _does _done _down _downed _downing _downs _during _e _each _early _either _end _ended _ending _ends _enough _even _evenly _ever _every _everybody _everyone _everything _everywhere _f _face _faces _fact _facts _far _felt _few _find _finds _first _for _four _from _full _fully _furhered _further _furthering _furthers _g _gave _general _generally _get _gets _give _given _gives _go _going _good _goods _got _great _greater _greatest _group _grouped _grouping _groups _h _had _has _have _having _he _her _here _herself _high _higher _highest _him _himself _his _how _however _i _if _important _in _interest _interested _interesting _interests _into _is _it _its _itself _j _just _k _keep _keeps _kind _knew _know _known _knows _l _large _largely _last _lastest _later _leastless _let _lets _like _likely _long _longer _longest _m _made _make _making _man _many _may _me _member _members _men _might _more _most _mostly _mr _mrs _much _must _my _myself _n _necessary _need _needed _needing _needs _never _new _newer _newest _next _no _nobody _non _noone _not _nothing _now _nowhere _number _numbered _numbering _numbers _o _of _off _often _old _older _oldest _on _once _one _only _open _opened _opening _opens _or _order _orderd _ordering _orders _other _others _our _out _over _p _part _parted _parting _parts _per _perhaps _place _places _point _pointed _pointing _points _possible _present _presented _presenting _presents _problem _problems _put _puts _q _quite _r _rather _really _right _room _rooms _s _said _same _saw _say _says _second _seconds _see _seem _seemed _seeming _seems _sees _several _shall _she _should _show _showed _showing _shows _side _sides _since _small _smaller _smallest _so _some _somebody _someone _something _somewhere _state _states _still _such _sure _t _take _taken _than _that _the _their _them _then _there _therefore _these _they _thing _things _think _thinks _this _those _though _thought _thoughts _three _through _thus _to _today _together _too _took _toward _turn _turned _turning _turns _two _u _under _until _up _upon _us _use _used _uses _v _very _w _want _wanted _wanting _wants _was _way _ways _we _well _wells _went _were _what _when _where _whether _which _while _whole _whose _whoss _why _will _with _within _without _work _worked _working _works _would _x _y _year _years _yet _you _young _younger _youngest _your _yours _z _가 _가운데 _갈 ; _갑 _걔 _거 _건 ; _걸 _것 겉 _게 _겨 _겸 _겹 _경 _곁 _계 _고 _곱 _곳 _곳곳 _과 _곽 _굄 _구 _권 _그 _그간 _그것 _그곳 _그녀 _그달 _그당시 _그대 _그대신 _그동안 _그들 _그들대로 _그때 _그런고 _그런날 _그런데서 _그런줄 _그럴수록 _그로 _그무렵 _그외 _그이 _그전 _그전날 _그쪽 _근 *글 _급 _깁 _깡 *꽃 ; _꽝 꾐 _끗 _낌 _나 _낙 _낟 _낱 _내게 _내년초 _내달 _내부 _냥 _너 _너나마 _너로 _너와 _너희 _너희대로 _너희들 _네 _네번 _네째 _네탓 _넷 _넷째 _년 _년간 _년도 _녘 _노 놈 _놉 _누가 _누구 _누구누구 _누군가 _뉘 _닢 _다섯째 _다음달 _다음주 _닥 ; _답 _당분간 _대다수 ; _댁 ; _덤 _덧 _데 ; _돗 _되 _두 _둔 _둘 _둘째 _둥 _뒤 _뒷받침 _듯 _등 _따름 _따위 _딴 _때 _때문 ; _땡 _떼 _뜀 ; _런 ; _룰 ; _룸 _리 _릴 _마 _마련 _마리 ; _마지막 _마찬가지 _막 _만 ; _만원 ; _만원씩 _만큼 _맏 ; _맘 ; _맴 _메 _멸 _몇 _무엇 _묶음 _물론 _뭇 _뭣 _밑 ; _바 _밖 ; _백 ; _백만 ; _백만원 _밸 _번 _번째 별안간 ; _볏 ; _본 ; _봉 ; _분 ; *비타민A ; *비타민B ; *비타민C ; *비타민D ; *비타민E _빈 ; _빔 ; _빽 ; _뻥 ; _뼘 _뿐 _사 ; _삭 ; _삵 _샅 _서 _서로 _석 _섟 ; _섶 _세 _세째 ; _셈 _셋 _셋째 속 ; _송 _수 _수십 _수십개 ; _숱 _쉬 쉰 _스스로 _승 식 십 ; _쌈 ; _쌍 _씀 ; _씹 아홉째 _안 _앎 _압 _앵 _야 _얘 _어느편 _어디 _어디론지 _어떤때 ; _억원 엠 _여 _여러가지 _여럿 _여섯째 역 _열째 옆 ; _예 _예년때 _오 _온 _올 _올해 ; _옴 ; _옹 _왜 _요즘 _우 ; _우리 _우리들 _우선 _운운 _움 _움직임 월 *웹 _위해서 ; *윈도95 ; *윈도95시스템 ; *윈도NT _유 _육 _율 _으뜸 ; _을 _음 _이것 _이곳 _이기 _이날 _이달 _이달초 _이듬 _이듬달 _이때 _이런저런 _이런줄 _이번 _이번분 _일곱째 ; _임 _잇 ; _작 ; _잔 _잘 ; _잭 ; _잽 ; _쟁 _쟤 _저것 _저곳 _저기 _저기대 _저긴 _저도 _저런날 _저런줄 _저렴 _저마 _저쪽 _저하 _저희 _적극적 _전날 _전년 _전부 _전부문 _전일 _전체적 _절절 ; _접 _제 _제나름 ; _존 ; _좆 ; _좌 ; _죄 _줄곳 ; _줌 _중점적 ; _쥔 _증 _지 _지난해 _직 _짓 _쪽 ; _찬 ; _채 ; _챙 ; _척 ; _천만 ; _천명 ; _천원 _첫날 _첫째 ; _촉 _최 _최근 ; _충 _취 _층 _치 ; _칭 ; _칸 ; _캡 _컷 ; _켜 ; _콕 _쾌 ; _쿡 ;_크기 ; _큰폭 ; _킥 _타 _탓 _태 ; _토 _톡 ; _톤 _톨 ; _톳 ; _퇴 _투 _퉁 ; _판 ; _패 ; _팽 *페르시아만 _편 _평 ;_평상시 포 폭 ; _폼 _푸르름 ; _푼 픽 ; _필 _하 _하나 _하나둘 _한 _한가운데 _한가지 _한곳 ; *한국HP ; *한국IBM ; *한국IBM연구소 _한마디 _한번 _한쪽 _한편 _할 ; _합 ; _항 *핵 ; _행 ;_향후 _허 _혁 ; _현 ; _호 ; _홉 ; _홍 ; _홑 ; _화 _확 _환 ; _황 ; _홰 ; _획 ; _횡 _후 ; _훅 _휘 ; _흑 _힐 *힘 ; ;=======================[ 불용어, 특수색인어 사전 끝 ]==================== ;
|