[ELK] 4. Elasticsearch 검색하기

Elasticsearch를 이용해 검색

사전준비

Elasticsearch에서 제공하는 대량의 테스트 데이터를 Bulk API를 호출하여 저장해준다.

Data: data.json

$ docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" docker.elastic.co/elasticsearch/elasticsearch:7.10.2
$ curl -XPOST 'localhost:9200/account/_bulk?pretty' -H "Content-Type: application/json" --data-binary "@data.json"

후 http://localhost:9200/account/_search 로 접속 해본다.

검색 Response

{
    "took": "검색하는데 걸린 시간(ms)",
    "timed_out": "시간 초과 여부 (true/false)",
    "_shards": {
        "total": "검색한 shard 수",
        "successful": "검색에 성공한 shard 수",
        "skipped": 0,
        "failed": "검색에 실패한 shard 수"
    },
    "hits" : {
        "total": "검색 된 문서의 총 개수",
        "max_score": "검색 조건과 일치한 점수의 최대 값",
        "hits" : [ 
            {
                "_index": "인덱스 이름",
                "_type": "_doc", # 7.x부터 _doc으로 통일,
                "_id": "id",
                "_score": "해당 document가 검색 쿼리와 일치하는 상대적인 값",
                "_source": {
                    # 데이터
                }
            }
        ]
    }
}

URL에 파라미터를 넘기는 방법

http://localhost:9200/account/_search?q=gender:F&size=1&from=1

저장된 계좌정보중에서 성별이 여자인 결과를 1번째부터 1개만 가져오기 (기본은 0번째부터)

Query DSL

json 파일에 쿼리를 작성하여 넘기는 방법. 더욱 상세한 표현이 가능

사용법

$ curl -XGET 'localhost:9200/account/_search?pretty' -H 'Content-Type: application/json' -d @query.json

query.json 에 검색 쿼리를 작성한다.

전체 검색 match_all

// match_all.json
{
    "query": {
        "match_all": {}
    }
}

기본 필드 검색 match

// match.json
{
    "query": {
        "match": {
            "gender": "F"
        }
    }
}

True/False 검색 bool

  • must: bool must 절에 지정된 모든 쿼리가 일치하는 document 조회
  • must_not: bool must_not 절에 지정된 모든 쿼리가 일치하지 않는 document 조회
  • should: bool should 절에 지정된 모든 쿼리 중 하나라도 일치하는 document 조회
  • filter: filter절에 지정된 모든 쿼리와 일치하는 documnet를 조회 (score 무시)
// bool.json
{
    "query": {
        "bool": {
            "must": [
                { "match": { "firstname": "Concetta" } }
            ],
            "must_not": [
                { "match": { "gender": "M" } }
            ]
        }
    }
}
{
    "from": 0,
    "size": 1000,
    "query": {
        "bool": {
            "should": [ {
                    "bool": {
                        "must": {
                            "term": { "address": "street" }
                        },
                        "boost": 2.0
                    }
                }, {
                    "bool": {
                        "must": {
                            "term": { "address": "place" }
                        }
                    }
                }
            ]
        }
    }
  }
  

boost : 가중치

조건절 검색 filter

// filter.json
{
    "query": {
        "bool": {
            "filter": {
                "match": { "firstname": "Concetta" }
            }
        }
    }
}

범위 검색 range

  • gte: greater equal
  • gt: greater than
  • lte: less equal
  • ls: less
// range.json
{
    "query": {
        "bool": {
            "filter": {
                "range": {
                    "balance": {
                        "gte": 10000,
                        "lte": 20000
                    }
                }
            }
        }
    }
}

역색인(Inverted Index) 검색 term, terms

역색인에 있는 토큰 중 키워드가 포함된 documnet를 조회

“a b c”라는 문자열은 [“a”, “b”, “c”] 로 역색인 되기 때문에 “a b c” 로는 검색이 안된다.

// term.json
{
    "query": {
        "term": {
            "address": "street"
        }
    }
}
// terms.json
{
    "query": {
        "terms": {
            "address": ["street", "place"]
        }
    }
}

공통 옵션 size, from

{
    "from": 0,
    "size": 3,
    "query": {
        "match_all": {}
    }
}

from: sql의 offset

size: sql의 limit

공통 옵션 sort

{
    "sort": [
        { "age": "asc" },
        { "_score": "desc" }
    ],
    "query": {
        "match_all": {}
    }
}

age에 대해 오름차순으로 정렬 후, _score에 대해 내림차순으로 정렬

  • 정렬을 사용하지 않을 경우 기본 정렬은 _score 내림차순

집계 하기 aggs (aggregations)

{
    "query": {
        "term": {
            "address": "street"
        }
    },
    "aggs": {
        "balance_avg": { # response  명시할 통계 결과 필드명
            "avg" : { # 집계 타입 (sum, 등)
                "field" : "balance" # 어떤 필드를 통계  것인지
            }
        }
    }
}