이번 실습에서는 가장 많이 활용되고 있는 검색엔진 솔루션 중 하나인 Elasticsearch를 설치하고 구동해 보자.
데몬으로 구동한 후 가장 간단한 형태의 색인 및 검색 테스트를 통해 정상적으로 동작하는지 확인해 보자.
일단 데이터셋은 cnn_dailymail로 약 27만 개의 cnn 뉴스 데이터로 진행해 볼 것이다.
1. Elasticsearch 설치
Elasticsearch를 노트북 환경에 설치한다.
# Elasticsearch Python 패키지 설치
!pip install elasticsearch==8.8.0
# Elasticsearch 8.8.0 다운로드 및 압축 풀기
# 리눅스용 엘라스틱서치 서버 설치를 위한 패키지 다운로드
!wget -q https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.8.0-linux-x86_64.tar.gz
!tar -xzf elasticsearch-8.8.0-linux-x86_64.tar.gz
!ls elasticsearch-8.8.0/
완료되면 elasticsearch 폴더 아래 실제 필요한 파일들이 설치된 걸 확인할 수 있다.
다음으로 구글 코랩에서 서버 구동과 리소스 제한을 위해서 필요한 작업을 해준다.
# 코랩 노트북 환경에서 서버 구동을 위해서 PPID 1의 백그라운드 데몬 프로세스가 해당 폴더에 접근이 가능하도록 소유자 변경
!sudo chown -R daemon:daemon elasticsearch-8.8.0/
# 코랩 노트북 환경에서 서버 구동을 위한 리소스 제한/격리를 위해 아래 명령 수행
!umount /sys/fs/cgroup
!apt install cgroup-tools
2. Elasticsearch 구동
이제 엘라스틱서치의 데몬 인스턴스를 만들어보자.
import os
from elasticsearch import Elasticsearch, helpers
import numpy as np
import pandas as pd
import json
from subprocess import Popen, PIPE, STDOUT
es_server = Popen(['elasticsearch-8.8.0/bin/elasticsearch'],
stdout=PIPE, stderr=STDOUT,
preexec_fn=lambda: os.setuid(1) # as daemon
)
# 인스턴스를 로드하는 데 약간의 시간이 걸림
import time
time.sleep(30)
이제 정상적으로 데몬이 실행됐는지 확인해 보자.
# 데몬이 구동되었는지 확인 (세개의 daemon process가 있어야 함)
!ps -ef | grep elasticsearch
❓ 왜 daemon process가 3개나 실행되고 있어야 할까?
Elasticsearch를 실행하면 일반적으로 3개의 프로세스가 나타난다. 이는 메인 프로세스, 자식 프로세스, 그리고 이를 제어하는 관리 프로세스 때문이다. 메인 프로세스는 핵심 기능을 수행하고, 자식 프로세스는 JVM 관리나 병렬 작업을 처리하며, 관리 프로세스는 상태를 모니터링하고 오류를 기록한다. 이 3개의 프로세스는 Elasticsearch의 안정성과 성능을 위해 필수적이다.
데몬이 설치되었다고 해서 바로 es에 들어가서 명령어를 실행할 순 없다.
그전에 비밀번호 설정 단계가 필요하다.
명령 실행 후 "Please confirm that you would like to continue"에서 y 입력 필요
!/content/elasticsearch-8.8.0/bin/elasticsearch-setup-passwords auto -url "https://localhost:9200"
이렇게 나온 비밀번호 중에서 가장 아래 수정된 비밀번호를 아래 명령어에 복사 붙여 넣기 해준다.
username = 'elastic'
# 위 명령 실행 결과의 마지막 부분인 PASSWORD elastic 값으로 교체 필요
password = '15Fg7u0gPf393wgNAnVd'
es = Elasticsearch(['https://localhost:9200'], basic_auth=(username, password), ca_certs="/content/elasticsearch-8.8.0/config/certs/http_ca.crt")
resp = dict(es.info())
resp
3. 색인 및 검색 명령 실행
이제 실제 색인 및 검색을 하기 전에 데이터셋을 다운로드하여 주자.
# 데이터셋 사용을 위한 huggingface datasets 패키지 인스톨
!pip install datasets -q
위에서 데이터셋 사용을 위한 패키지를 설치했으니 이제 실제 데이터셋을 다운로드해보자.
# 실제 다운로드 및 데이터셋 로딩
import datasets
dataset = datasets.load_dataset("cnn_dailymail", "3.0.0", split="train").to_pandas()
dataset.drop("id", axis=1, inplace=True)
print(f"shape of dataset: {dataset.shape}")
dataset.head()
다음으로 이제 ES 인덱스 설정과 매핑을 정의해 주자.
현재 article, highlights로 이루어져 있고 둘 다 문자형이라 다음과 같이 설정해 준다. settings 같은 건 필수적으로 필요한 사항은 아니지만 일단 shard를 하나, replica는 사용하지 않는 걸로 세팅해 줬다.
settings = {
"settings":{
"number_of_shards":1,
"number_of_replicas":0
},
"mappings":{
"properties":{
"article":{
"type":"text"
},
"highlights":{
"type":"text"
}
}
}
}
다음으로 실제 ES 색인을 위한 JSON 형식의 딕셔너리를 생성하는 함수를 만들어 주자. 그래서 아까 받아온 데이터를 한번 더 실제 json으로 색인해 줄 수 있는 함수라고 할 수 있다.
def json_formatter(dataset, index_name):
"""
이 함수는 Elasticsearch 색인을 위한 JSON 형식의 딕셔너리를 생성하는 데 사용됩니다.
Args:
dataset: 이 함수를 적용하려는 데이터입니다.
index_name: Elasticsearch의 인덱스 이름입니다.
"""
try:
List = []
columns = dataset.columns
for idx, row in dataset.iterrows():
dic = {}
dic['_index'] = index_name
source = {}
for i in dataset.columns:
source[i] = row[i]
dic['_source'] = source
List.append(dic)
return List
except Exception as e:
print("There is a problem: {}".format(e))
다음 코드는 실제 색인을 하나 생성해 주는 코드다. 아까 선언한 settings를 인자로 전달해 준다.
이 명령어가 끝나면 ES에 실제로 news_index라는 이름으로 인덱스(RDB로 따지면 테이블)가 생성된다.
MY_INDEX = es.indices.create(index="news_index", body=settings)
MY_INDEX
그럼 news_index 인덱스에 실제 데이터를 넣어보자. 일단 가져온 데이터가 너무 많기 때문에 앞쪽 100개만 잘라서 사용해보려고 한다.
아까 정의한 json_formatter 함수를 이용해 실제 사용할 수 있는 json 형태로 바꿔주자.
# 너무 많아서 100개만 사용
dataset = dataset[:100]
json_Formatted_dataset = json_formatter(dataset=dataset, index_name='news_index')
json_Formatted_dataset[0]
바뀐 결과를 확인해 보면 다음과 같다.
이 외에도 elasticsearch.helpers API를 사용해서 색인을 빠르게 진행할 수도 있다.
res = helpers.bulk(es, json_Formatted_dataset[:100])
res
위 결과에서 100으로 보이는 숫자는 정삭적으로 색인이 완료된 문서의 개수를 나타낸다.
그럼 이제 정상적으로 색인이 완료된 데이터중에서 10개를 가져와보는 코드를 작성해 보자.
이 명령어는 실제 검색은 아니고 match_all 쿼리를 통해 모든 문서와 매치를 하고 내부적으로 score 계산을 안 하고 모두 score를 1.0으로 간주하는 방법이다.
# 색인된 문서중 10개의 데이터 샘플 가져오기
query = es.search(
index="news_index",
body={
"size":10,
"query": {
# 모든 문서가 매치된다는 의미 (_socre는 모두 1.0)
"match_all":{}
}
}
)
output = pd.json_normalize((query['hits']['hits']))
output
바로 다음글에서 한국어 형태소 분석기인 Nori를 이용해서 색인하는 과정을 살펴보자!
'Tools' 카테고리의 다른 글
Vector 유사도 검색 - Faiss (0) | 2024.12.05 |
---|---|
Vector 유사도 검색 - Elasticsearch (0) | 2024.12.05 |
구글 코랩에서 Elasticsearch Nori Query DSL 사용해서 검색하기 (1) | 2024.12.04 |
구글 코랩에서 Elasticsearch Nori 사용해보기 (ES 공식 지원 한글 형태소 분석기) (0) | 2024.12.04 |
Slack과 GitHub 연동 (2) | 2023.10.25 |