잇츠 스터디 4기에서 elastic search 스터디를 진행 하면서, elastic 가이드 북 중 QueryDSL 부분을 정리한 글입니다.
검색과 쿼리 - QueryDSL
Elastic Search 는 사용자가 여러가지 검색 조건을 통한 검색을 할 수 있도록 다양한 쿼리를 제공하고 있다.
이러한 쿼리를 QueryDSL 이라고 칭함.
모두 json 형식으로 입력해야 함.
풀 텍스트 쿼리?
실제로 검색에 사용되는 검색어인 Term 으로 분석 과정을 거쳐 저장하기 때문에 검색 시, 대소문자, 단수, 복수, 원형 여부에 관계 없이 검색이 가능함.
- match_all
- match
- match_phrase
- query_string
- match_all
- 만약 검색시 쿼리를 넣지 않으면 default 로 해당 쿼리를 이용해 검색해 줌.
- 해당 인덱스의 모든 도큐먼트를 검색함.
- match
- 특정 단어가 포함된 모든 문서를 검색한다.
- match 쿼리에 여러개의 검색어 작성시 ⇒ OR 조건 적용
- 만약 AND 조건을 적용하고 싶다면?operator 옵션 적용
- operator 옵션 적용
GET my_index/_search
{
"query": {
"match": {
"message": "quick dog"
}
}
}
// quick 과 dog 중 어떤 하나라도 포함되면 검색
GET my_index/_search
{
"query": {
"match": {
"message": {
"query": "quick dog",
"operator": "and" //적용
}
}
}
}
// quick 과 dog 둘다 들어간 것만 검색
3. match_phrase
quick dog 이라는 구문을 공백 포함하여 정확히 검색 용
slop : 단어 사이에 다른 검색어가 끼어드는 것을 허용
GET my_index/_search
{
"query": {
"match_phrase": {
"message": "lazy dog"
}
}
}
GET my_index/_search
{
"query": {
"match_phrase": {
"message": {
"query": "lazy dog",
"slop": 1
}
}
}
}
4. query string
- OR 이나 AND 같은 operator 기준으로 query string을 구분함.
- operator 기준으로 나뉘어 문장을 각자 독립적으로 분석함.
- 와일드 카드나, 복합 필드를 query 할 때 사용 가능.
Bool 복합 쿼리 - Bool Query
앞서 배운 여러 쿼리들을 조합하기 위해서 사용.
상위에 bool 이라고 명시하고, 그 안에 다른 쿼리들을 넣음.
- must : 쿼리가 참인 도큐먼트들을 검색합니다.
- must_not : 쿼리가 거짓인 도큐먼트들을 검색합니다.
- should : 검색 결과 중 이 쿼리에 해당하는 도큐먼트의 점수를 높입니다.
- filter : 쿼리가 참인 도큐먼트를 검색하지만 스코어를 계산하지 않습니다. must 보다 검색 속도가 빠르고 캐싱이 가능합니다.
GET <인덱스명>/_search
{
"query": {
"bool": {
"must": [
{ <쿼리> }, …
],
"must_not": [
{ <쿼리> }, …
],
"should": [
{ <쿼리> }, …
],
"filter": [
{ <쿼리> }, …
]
}
}
}
- quick 과 일치하고, lazy dog 과 일치하지 않는 모든 결과 값을 조회한다
GET my_index/_search
{
"query": {
"bool": {
"must_not": [
{
"match": {
"message": "quick"
}
},
{
"match_phrase": {
"message": "lazy dog"
}
}
]
}
}
}
must 랑 should 를 섞어쓰면 주의해야 함.
문제
{
"query": {
"bool": {
"should": [
{
"match": {
"name": "Messi"
}
}
],
"filter": [
{
"match": {
"sports": "basketball"
}
}
]
}
}
}
기대했던 것
- name 이 Messi 인 결과 중에 sports 가 basketball인 값을 가져온다.
결과
- 하지만 should 조건은 무시되고 sports에 basketball만 있는 애들을 가져옴.
- must 나 filter 쿼리가 없다면 minimum_should_match는 디폴트 값이 0
- 하나라도 일치 안해도 상관 없다는 뜻이니깐, must 조건만 참이여도 반환하게 됨.
- minimun_should_match 가 1이라도 돼야, 일치하는게 1개라도 있으면 참을 반환하게 됨
해결방안
- minimum_should_match 값을 1로 변경
- should match대신 must 를 사용
정확도(Relevancy)?
RDBMS 는 쿼리 조건에 부합하는 것만 결과를 가져오는 것.
각 결과들이 얼마나 정확한지에 대한 판단은 불가능.
Elastic search 는 얼마나 비슷한지 판단하는 알고리즘이 있음.
이 정확도를 기반으로 사용자가 원하는 데이터 조회 가능.
- score
- 검색 조건과 얼마나 일치하는지
- 점수가 높은 순으로 결과를 보여줌.
- 각 결과에서 _score 부분에 표시됨.
max_score 에서는 전체 결과 중 가장 높은 점수가 표시됨.
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 5,
"relation" : "eq"
},
"max_score" : 0.8762741,
"hits" : [
{
"_index" : "my_index",
"_type" : "_doc",
"_id" : "3",
"_score" : 0.8762741,
"_source" : {
"message" : "The quick brown fox jumps over the quick dog"
}
},
{
"_index" : "my_index",
"_type" : "_doc",
"_id" : "2",
"_score" : 0.6744513,
"_source" : {
"message" : "The quick brown fox jumps over the lazy dog"
}
},
{
"_index" : "my_index",
"_type" : "_doc",
"_id" : "1",
"_score" : 0.6173784,
"_source" : {
"message" : "The quick brown fox"
}
}
}
]
}
}
score 을 매기는데 사용되는 알고리즘 = BM25 알고리즘
BM25 알고리즘?
- BM : Best Matching 알고리즘
TF (Term Frequency)
- 쥬라기 공원이 5번 들어있는 페이지보다 10번 든 페이지가 더 확률이 높다.
- 다다익선
- 25개 이후로는 비슷한 점수 부여
IDF (Inverse Document Frequency)
- 자신을 포함한 도큐먼트 개수가 많을수록 그 텀의 자신의 점수가 감소하는 것.
- 전체에서 쥬라기는 10번, 공원은 100번있는 단어라면 쥬라기가 더 중요한 term
- IDF 가 작다 == 점수가 낮다.
Field Length
- 텍스트 길이가 더 짧을수록 더 점수가 높음.
Bool : Should
검색 점수를 조정하기 위해 사용할 수 있음.
이 결과들 중 lazy 가 포함된 결과에 가중치를 줘서 상위로 올리고 싶으면
다음과 같이 should 안에 lazy 를 찾는 검색을 추가합니다.
GET my_index/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"message": "fox"
}
}
],
"should": [
{
"match": {
"message": "lazy"
}
}
]
}
}
}
정확값 쿼리(Exact Value Query)
풀 텍스트 검색은 스코어 점수 기반으로 정확도 기반으로 높은 결과부터 조회됨.
하지만, 참 / 거짓만 판단하여 결과를 조회할 수 있기도 함.
- bool : filterEx. 쇼핑몰에서 검색어로 정확도가 높은 상품명을 검색하면서, 생산 업체를 다시 필터링하는 용도
- 하위 쿼리를 사용하면 스코어에 영향을 주지 않는다.
- keyword스코어는 계산하지 않고, 정확도만 따지기 때문에 스코어가 0.0 , filter 안에 넣고 사용할 것
- 공백, 대소문자까지 완전히 일치하는 데이터를 리턴함.
범위 쿼리(Range Query)
문자열 필드 외에 숫자나, 날짜 형식들의 저장이 가능함.
정확도를 계산하지 않는다.
가깝거나 멀다고 정확도가 변하진 않음.
하지만 가깝거나 멂 정도에 따라 정확도를 부여하고 싶다면 function_score 적용 가능
Elastic Search 성능 튜닝
- Bulk 요청 사용
- 한번에 여러 문서를 인덱싱할 수 있게해줌.
- 단일 문서 인덱싱보다 개선됨
- 적절한 벌크 요청을 위해서는 밴치마크 테스트 수행
- 속도가 정체되는 시점을 찾기.
- 너무 큰 bulk는 메모리 압박을 초래함
- 여러 작업자 / 스레드 사용.
- 단일 스레드로 bulk 요청을 보내는 것은 전체 리소스를 활용하기 어려움.
- 여러 스레드나 프로세스를 이용하면 데이터 전송 속도를 높임
- I /O 나 CPU 가 포화 상태에 이를 때 최적의 스레드 수를 찾기.
- refresh 간격 설정?
- 색인된 문서를 검색 가능하게 만드는 작업
- 색인될 때 메모리 버퍼에 저장되고, refresh가 발생할 때 이 메모리 버퍼에 있는 문서들이 새로운 "검색 가능한" 세그먼트로 변환
- 원래는 1초마다 반복하지만, 이걸 조절하면 좋음 ex. 30초
- 초기 데이터 로드 시, refresh 와 replica 비활성화
- 메모리,디스크 관련
- I/O 작업을 버퍼링하는데 파일 시스템 캐시를 사용하므로 전체 메모리의 절반을 이 캐시용으로 할당
- 더 빠른 SSD 를 사용하거나 로컬 디스크를 사용
- 버퍼 크기를 512MB 정도 각 샤드에 할당하면 성능이 개선
- jvm 메모리의 10퍼센트가 주로 할당됨.
- 느린 쿼리
- slow log를 켜서 실행 속도가 느린 쿼리를 식별 가능.