목표
Elasticsearch
와 fscrawler
를 활용하여 문서 검색 시스템을 구축한다.
Elasticsearch ?
Elasticsearch는 Apache Lucene( 아파치 루씬 ) 기반의 Java 오픈소스 분산 검색 엔진으로 대용량 데이터를 신속하게 저장, 검색 및 분석할 수 있는 기능을 제공한다. 데이터를 실시간으로 처리하여 색인할 수 있고 RESTful API를 통해 데이터에 쉽게 액세스 할 수 있다.
fscrawler ?
FSCrawler는 Elasticsearch를 위한 도구 중 하나로 파일 시스템의 다양한 형식의 문서(예: 텍스트 파일, PDF, 워드 문서 등)를 검색 가능한 형태로 변환하여 Elasticsearch에 색인하는 역할을 한다.
개발환경
Use | Description |
---|---|
Elasticsearch | 검색 엔진 |
fscrawler | 문서 파일 색인 추출 |
Kibana | Elasticsearch 시각화 도구 |
analysis-nori | Elasticsearch의 한국어 형태소 분석기 |
nextjs | web 개발 프레임워크로 사용 |
docker | 컨테이너 기반 서비스로 docker를 활용 |
vscode | 소스 편집 툴 |
프로젝트 가져오기
아래 프로젝트에서 소스를 clone 한다.
1
$ git clone https://github.com/surfharu/withsearch.git
주요 파일 구성은 다음과 같다.
폴더 및 파일 | 설명 | |
---|---|---|
elasticsearch | 한국어 형태 분석기를 포함한 elasticsearch 이미지 생성하기 위한 폴더 | |
config | 환경 설정 파일 (elasticsearch & fscrawler) | |
web | 검색을 위한 web 페이지 (nextjs로 구성) | |
documents | 검색을 위한 문서들을 저장할 위치 | |
logs | 주요 서비스 로그 위치 | |
docker-compose.yml | 서비스 docker-compose 설정 파일 |
프로젝트 설치 및 셋팅
먼저 elasticsearch 에 analysis-nori
플러그인을 추가하여 도커 이미지를 생성한다.
1
2
$ cd elasticsearch
$ docker build -t custom-elastic:latest .
web 서비스를 위한 도커 이미지를 생성한다. (nextjs
프레임워크를 이용하여 개발함)
1
2
$ cd web
$ docker build -t custom-web:latest .
다음으로 config 폴더 아래 elasticsearch, fscrawler 관련 설정을 해준다.
config/fscrawer/_default/7/_settings.json
파일에 FSCrawler가 한국어 형태소 분석기(nori_analyzer)
를 활용할 수 있도록 설정하였다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
"settings": {
"number_of_shards": 1,
"index.mapping.total_fields.limit": 2000,
"analysis": {
"analyzer": {
"fscrawler_path": {
"tokenizer": "fscrawler_path"
},
"nori_analyzer": {
"type":"custom",
"tokenizer":"korean_nori_tokenizer"
}
},
"tokenizer": {
"fscrawler_path": {
"type": "path_hierarchy"
},
"korean_nori_tokenizer":{
"type":"nori_tokenizer",
"decompound_mode":"mixed",
"user_dictionary":"userdict_ko.txt"
}
}
}
},
config/fscrawer/haru/_settings.yaml
에 문서 경로 및 업데이트 시간을 설정한다.
name
은 인덱스명이므로 사용자설정에 맞게 입력한다. update_rate
은 5m
으로 5분 주기로 문서를 읽어들이도록 설정하였다.
보다 자세한 설정 방법은 fscrawler Site를 참조한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
name: "haru"
fs:
url: "/tmp/documents"
update_rate: "5m"
json_support: false
filename_as_id: true
add_filesize: true
remove_deleted: true
add_as_inner_object: false
store_source: true
index_content: true
attributes_support: false
raw_metadata: true
xml_support: false
index_folders: true
lang_detect: false
continue_on_error: false
elasticsearch:
nodes:
- url: "http://elasticsearch:9200"
bulk_size: 1000
flush_interval: "5s"
byte_size: "10mb"
config/elasticsearch/elasticsearch.yml
에 CORS 설정을 추가해준다. 동일 호스트는 허용하도록 설정하였다.
1
2
http.cors.enabled: true
http.cors.allow-origin: /https?:\/\/localhost(:[0-9]+)?/
docker-compose.yml
파일을 설정한다. 운영 서비스는 아니므로 싱글노드로 구성하여 설정하였다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
version: '2.2'
services:
elasticsearch:
image: custom-elastic
container_name: elasticsearch
environment:
- discovery.type=single-node
- cluster.name=single-cluster
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xmx2g -Xms2g"
healthcheck:
test: ["CMD-SHELL", "curl --silent --fail localhost:9200/_cluster/health || exit 1"]
interval: 20s
timeout: 20s
retries: 3
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- esdata01:/usr/share/elasticsearch/data
- ${PWD}/config/elasticsearch/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
ports:
- 9200:9200
networks:
- elastic
# Kibana
kibana:
image: docker.elastic.co/kibana/kibana:7.9.2
container_name: kibana
environment:
ELASTICSEARCH_URL: http://elasticsearch:9200
ELASTICSEARCH_HOSTS: http://elasticsearch:9200
ports:
- "5601:5601"
networks:
- elastic
depends_on:
elasticsearch:
condition: service_healthy
# FSCrawler
fscrawler:
image: dadoonet/fscrawler
container_name: fscrawler
volumes:
- ${PWD}/config/fscrawler:/root/.fscrawler
- ${PWD}/documents:/tmp/documents
- ${PWD}/logs/fscrawler:/usr/share/fscrawler/logs
environment:
- "FS_JAVA_OPTS=-Dlog4j.configurationFile=/usr/share/fscrawler/config/log4j2.xml"
networks:
- elastic
command: fscrawler haru --trace
depends_on:
elasticsearch:
condition: service_healthy
# search web service
web:
image: custom-web:latest
ports:
- "3000:3000"
networks:
- elastic
depends_on:
elasticsearch:
condition: service_healthy
volumes:
esdata01:
driver: local
networks:
elastic:
driver: bridge
서비스를 기동한다.
1
$ docker-compose up -d
검색할 문서를 documents
폴더에 넣고 5분을 기다린다.
서비스를 위한 준비는 끝났다.
서비스 확인
아래 주소에 접속하여 각각의 서비스를 확인한다.
서비스명 | 접속주소 |
---|---|
Elasticsearch | http://localhost:9200 |
Kibana | http://localhost:5601 |
Web | http://localhost:3000 |
Web에서 검색 내용을 입력하면 유사도 순으로 검색 결과가 출력되는 것을 확인할 수 있다.
elasticsearch 주요 Restful API
- 현재
haru 인덱스
에 등록된 문서의 수를 리턴한다.1
(GET) http://localhost:9200/haru/_count
- 문서를 검색한다.
1
(GET) http://localhost:9200/haru/_search?size=10000&q=검색문장
- Insert (인덱스id 11에 해당 내용을 입력한다.)
1 2 3 4 5 6
(POST) http://localhost:9200/haru/_doc/11 { "first_name":"John", "last_name":"Smith", "age":25, }
- Select (인덱스 id가 11에 내용을 조회한다.)
1
(GET) http://localhost:9200/haru/_doc/11
- Delete (인덱스 id가 11인 데이터를 삭제한다.)
1
(DELETE) http://localhost:9200/haru/_doc/11