elastic search에서 서치와 페이지네이션
painless : Elastic Search 자체 스크립트 언어
params | 매개변수 Map |
ctx._source | 문서의 _source 값 Map으로 변환 |
ctx._now | timestamp를 ms로 변환한 값 |
ctx._index ctx._id ctx._type ctx._routing ctx._version |
메타데이터 |
Update by query
POST [인덱스명]/_update_by_query
쿼리 요청하면 문서를 일종의 스냅삿을 찍는다. 여기서 버전 충돌 문제가 생기면 conflicts 에 따라 작업한다. abort (기본값) 면 충돌 시 작업 중단하며, proceed 로 하면 무시하고 넘어간다.
scroll
운영중에 update 하면 부하 줄 수 있으므로 스로틀링을 통해 작업량을 조절
-scroll_size: 업데이트 전 먼저 검색을 수행하는데 한 번 검색 수행에 가져올 문서 개수
-scoll: 검색한 문서 가져오면 search context(검색 문맥)에 보존하는데, 얼마나 보존할지 지정. 한 배치(scoll_size) 작업에 필요한 시간만 지정하면 된다.
- 검색 문맥은 힙 메모리, 디스크 공간, file descriptor 를 차지하므로 너무 큰 값 X
검색
Term 쿼리
: text 타입일 때, 질의어는 normalizer 처리되고, text 타입 필드 값은 analyzer를 거쳐 역색인을 이용한다.
역색인 결과가 단일텀이고, 노멀라이저 거친 질의와 완전 일치하는 경우에만 검색 결과에 걸림
range 쿼리
: 문자열 필드 range 쿼리는 부하가 큰 쿼리로 분류
쿼리 문맥과 필터 문맥
필터 문맥(filter context) : 점수 X, 단순히 조건이 만족하는지 여부만 따짐
- filter, must_not, exists, range, constanc_score
쿼리 문맥(query context) : 유사도 점수 매김
- must, should, match, term 쿼리
쿼리 수행 순서
- must, must_not, filter, should 사이에 어떤 쿼리가 먼저 수행된다는 규칙이 없다.
루씬의 쿼리로 재조합에 비용 추정 후 유리할 것으로 생각되는 부분을 먼저 수행
- 쿼리 문맥이어도, 조건이 문서와 매치되는지를 참 거짓으로 판단, 이후 쿼리 문맥은 점수 계산, 필터 문맥은 점수 계산 X
- 쿼리 문맥이어도, 랭킹 안에 못 들것 같은 문서는 점수 계산 건너뜀
쿼리
모든 문서 검색
GET [INDEX_NAME]/_search
{
"query": {
"match_all" : {}
}
}
문서의 갯수 검색
GET [INDEX_NAME]/_count
{
"query": {
"match_all" : {}
}
}
조건 검색
특정 필드에 특정 값을 만족 하는 경우
GET [INDEX_NAME]/_count
{
"query": {
"match": {
"[필드명]": "[값]"
}
}
}
특정 필드의 값 조건 + 날짜 지정 범위
GET [INDEX_NAME]/_search
{
"size": 0, #출력결과 숨길때
"query": {
"bool": {
"must": [
{
"term": {
"[필드명]": "[값]"
}
},
{
"range": {
"@timestamp": {
"gte": "now-7d/d",
"lt": "now"
}
}
}
]
}
}
}
다중 조건 검색
GET [INDEX_NAME]/_count
{
"query": {
"bool": {
"must": [
{
"match": {
"[필드명1]": "[값1]"
}
},
{
"match": {
"[필드명2]": "[값2]"
}
},
{
"range": {
"@timestamp": {
"gte": "now-7d/d",
"lt": "now"
}
}
}
]
}
}
}
집계쿼리도 존재
페이지네이션
from, size (비추)
from, size 로 검색하면 from+size 개수 문서를 모두 검색한 뒤 잘라서 응답으로 보낸다.
그러면 CPU와 메모리 사용량을 크게 증가시킨다. 또 문제는 다음 페이지 검색할 때의 인덱스 변경이 있었다면 인덱스 상태가 동일하지 않기 때문에 누락될 수 도 있으므로 from,size 페이지네이션은 사용하지 말아햐 한다.
from+size 가 기본 1만이 넘어가면 검색은 수행이 거부된다.
scroll (전체 순회할 때 유용)
-검색 조건 만족하는 전체 문서 순회할 때 사용한다. 최초 검색 시의 문맥(search context) 이 유지되므로 중복이나 누락이 발생하지 않는다.
-"score":"1m" 에서 시간 설정은 배치와 배치 사이를 유지할 정도의 시간으로 지정하면 된다.
-정렬여부과 상관없다면 “sort”: [”_doc”] _doc 정렬을 지정하는 것이 좋다. 그러면 유사도 점수를 계산하지 않으며 정렬을 위한 별도의 자원도 사용하지 않아 성능 끌어올릴 수 있다.
search_after (추천)
동점 제거용(tiebreaker) 필드 정렬이 필요하다.
GET twitter/_search
{
"query": {
"match": {
"title": "elasticsearch"
}
},
"sort": [
{"date": "asc"},
{"tie_breaker_id": "asc"}
]
}
다음 페이지 검색 시, 가장 마지막 문서의 sort 값을 search_after 에 넣는다.
GET twitter/_search
{
"query": {
"match": {
"title": "elasticsearch"
}
},
"search_after": ["1463538857", "654323"],
"sort": [
{"date": "asc"},
{"tie_breaker_id": "asc"}
]
}
tiebreaker 필드로 _id 를 넣는 것은 좋지 않다. doc_values 가 꺼져 있어서 많은 메모리를 사용하기 때문이다.
필요하면 _id 값이 있는 새 필드를 파는 게 좋다.
point in time API
POST /my-index-000001/_pit?keep_alive=1m
검색 대상의 상태 고정할 때 사용한다. id 난수 값을 반환한다.
keep_alive: 상태 유지할 시간
{
"query": {
"match": {
"title": "elasticsearch"
}
},
"pit": {
"id": "[_pit 에서 준 값]",
"keep_alive": "1m"
},
"sort": [
{"date": "asc"}
]
}
pit 값으로 검색 시, 인덱스명 지정 X -> pit 지정 == 검색 대상 지정
earch_after 사용하려면 정렬 필드 최소 하나는 지정 필수
참고 및 출처
- 데이터 다루기 https://elsboo.tistory.com/77
- 실전 쿼리 요청 https://soyoung-new-challenge.tistory.com/97
- PIT : https://www.elastic.co/guide/en/elasticsearch/reference/current/point-in-time-api.html
- ES 페이징 : https://dev.to/lazypro/explaining-pagination-in-elasticsearch-2g26
- 페이징 방식 : https://blog.naver.com/occidere/222686762033
- 페이징 처리 : https://velog.io/@wjdgkrud/Elastic-paging-%EC%B2%98%EB%A6%AC
- offset bad : https://binux.tistory.com/148#comment14337039