Elastic Search
- 모든 데이터 색인을 통해 근 실시간으로 검색 및 분석이 가능한 검색 엔진(아파치 루신 기반)
- 텍스트 분석에 특화되어 있으며 웹 검색 엔진에서 주로 사용됨
- 데이터 수집, 보강, 저장, 분석, 시각화를 위한 도구 모음인 ELK 스택(Elasticsearch, Logstash, Kibana) 중 분석과 저장을 담당
ELK 사용하는 곳
- 어플리케이션 검색
- 로깅과 로그 분석
- 인프라 메트릭과 컨테이너 모니터링
- 어플리케이션 성능 모니터링
- etc...
기존 RDBMS 기반의 어플리케이션은 텍스트 검색이 어려움(like 검색을 사용하나 이는 동의어나 유의어에 대해서는 지원하지 않음), 그러나 엘라스틱서치는 문자열에 대한 동의, 유의, 전문검색(Full Text Search) 등을 지원함
사용하는 이유
- 오픈 소스 검색 엔진
- 역 인덱스 구조(색인 되어 있는 데이터에 대해서 문서 페이지에 대한 링크를 제공)
- 속도, 확장성, 복원력 등 광범위한 기능 제공
- 분산형 설계로 인한 데이터 보관의 안정성
ES는 검색엔진으로써 기능도 하지만 저장소로써의 역할도한다, RDBMS와의 용어차이를 간단히 정리하면 아래와 같다
ES와 RDBMS간의 구조 맵핑
ES는 기본적으로 http프로토콜로 접근이 가능한 Rest API를 통해 데이터 조작을 지원
동작원리
- ES에 index에 문서를 저장하면 메타데이터(문서의 내부 식별자, 버전 등)와 소스 데이터(문자열)를 key-value형태의 JSON으로 변형하여 저장.
- _doc API를 통해 단일데이터의 CRUD가 가능.
_doc 이 무엇인가?
http://<호스트>:<포트>/<인덱스>/<도큐먼트 타입>/<도큐먼트 id> 구조였으나, Elasticsearch 7.0 부터는 도큐먼트 타입 개념이 사라지고 대신 고정자 _doc 으로 접근해야 합니다.
기본 사용법(CRUD)
// 인덱스 생성
PUT <https://localhost:9200/{인덱스명}>
// 삽입
POST <https://localhost:9200/{인덱스명}/_doc/>{다큐먼트 번호}
{
"id" : "1",
"message" : "안녕!"
}
ex) <https://localhost:9200/test/_doc/1>
//조회
GET <https://localhost:9200/{인덱스명}/_doc/>{다큐먼트 번호}
//수정
//ES는 수정 요청이 들어오면 내부적으로 새로운 데이터를 생성하여 덮어 씌움
POST <https://localhost:9200/{인덱스명}/_update/>{다큐먼트 번호}
{
"doc" : {
"id" : "3",
"message" : "피카츄 vs 라이츄"
}
}
//삭제
DELETE <https://localhost:9200/{인덱스명}/_doc/>{다큐먼트 번호}
BULK 연산
POST <https://localhost:9200/**_bulk**>
// 맨 마지막은 빈 한 줄이 필요함
{"index":{"_index":"test", "_id":"1"}}
{"field":"value one", "newTitle":"news"}
{"index":{"_index":"test", "_id":"2"}}
{"field":"value two", "newsTitle":"title1", "newsContent":"content1"}
위의 CRUD까지는 JSON기반의 NoSQL과 비슷하나 ES에는 형태소 분할 저장이라는 특징이 존재.
- 형태소 분할을 통해 유의어, 동의어, 전문검색이 가능
- 단어 단위로 자르고 조사는 삭제함으로써 문서별로 의미 있는 데이터만 추출가능하고 이것을 기반으로 유사도 점수를 부여하여 검색한 것과 가장 가까운 문서를 찾을 수 있음.
어떤 식으로 형태소를 분할하는 지는 _analyze API를 통해 확인가능
request)
GET <https://localhost:9200/test/**_analyze**>
{
"tokenizer" : "standard",
"text" : "피트니스온에서 하는 헬스는 아주 바람직합니다. 왜냐하면 바람직하기 때문입니다."
}
response)
{
"tokens": [
{
"token": "피트니스온에서",
"start_offset": 0,
"end_offset": 7,
"type": "<HANGUL>",
"position": 0
},
{
"token": "하는",
"start_offset": 8,
"end_offset": 10,
"type": "<HANGUL>",
"position": 1
},
{
"token": "헬스는",
"start_offset": 11,
"end_offset": 14,
"type": "<HANGUL>",
"position": 2
},
{
"token": "아주",
"start_offset": 15,
"end_offset": 17,
"type": "<HANGUL>",
"position": 3
},
{
"token": "바람직합니다",
"start_offset": 18,
"end_offset": 24,
"type": "<HANGUL>",
"position": 4
},
{
"token": "왜냐하면",
"start_offset": 26,
"end_offset": 30,
"type": "<HANGUL>",
"position": 5
},
{
"token": "바람직하기",
"start_offset": 31,
"end_offset": 36,
"type": "<HANGUL>",
"position": 6
},
{
"token": "때문입니다",
"start_offset": 37,
"end_offset": 42,
"type": "<HANGUL>",
"position": 7
}
]
}
Inverted index(역색인)
- 위의 형태소 분석을 마친 데이터는 역색인 자료구조를 통해 저장되어 빠른 검색을 지원함
- 역색인 자료구조엔 특정한 토큰이 어떤 문서와 연관되어있는지 맵핑되어있음
POST
POST /test/_doc/1
{"message" : "황철순의 근육은 크다"}
POST
POST /test/_doc/2
{"message" : "핏블리의 근육도 크다"}
Term id
황철순 | 1 |
핏블리 | 2 |
근육 | 1, 2 |
크다 | 1, 2 |
- 이를 통해 검색 결과를 집계하고 반환할 때 높은 성능을 지님
검색
- 검색은 인덱스 단위로 이루어지며 GET {인덱스명}/_search 형식으로 사용, 쿼리를 입력하지 않으면 전체 도큐먼트를 찾는 match_all 검색을 사용
- hits.total.value : 검색 결과 전체에 해당하는 문서 개수
- hits.hits : [] 안에 정확도가 가장 높은 상위 10개의 문서가 나타남
GET <https://localhost:9200/{index}/_search?q={value}>
ex)
request) <https://localhost:9200/test/**_search?q=title1**>
response)
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,**(검색 결과 전체에 해당 하는 문서 개수)**
"relation": "eq"
},
"max_score": 0.9808291,
"hits": [
{
"_index": "test",
"_id": "2",
"_score": 0.9808291,
"_source": {
"field": "value two",
"newsTitle": "title1",
"newsContent": "content1"
}
}
]
}
}
- AND, OR, NOT의 사용이 가능하며 대문자로 입력 해야함
//AND 예시
request)
<https://localhost:9200/test/_search?q=**황철순 AND 핏블리**
response)
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 1.2814486,
"hits": [
{
"_index": "test",
"_id": "3",
"_score": 1.2814486,
"_source": {
"id": "3",
"message": "황철순 vs 핏블리"
}
}
]
}
}
반응형
- 찾고자 하는 필드에서 찾기
GET <https://localhost:9200/{인덱스}/_search?**q={필드명}:{value}**>
ex)
request) <https://localhost:9200/test/_search?**q=newsTitle:title1**>
response)
{
"took": 1,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 0.9808291,
"hits": [
{
"_index": "test",
"_id": "2",
"_score": 0.9808291,
"_source": {
"field": "value two",
"newsTitle": "title1",
"newsContent": "content1"
}
}
]
}
}
- 데이터 본문 검색
- 기본적으로 풀 텍스트 검색에 사용되는 가장 일반적인 쿼리
GET <https://localhost:9200/{인덱스}>
{
"query": {
"match": {
"{필드명}": "{value}"
}
}
}
## Referenece
반응형
'⌨Programming > Elastic Search' 카테고리의 다른 글
Elastic Search 설치(도커) (0) | 2024.02.21 |
---|