[엘라스틱서치] Elasticsearch in action 정리(2) - 데이터 검색
엘라스틱서치는 루씬 검색 기능을 모두 사용해서 데이터를 검색할 수 있도록 풍부한 API를 제공한다. 엘라스틱서치는 그 형식 덕분에 다양한 조합으로 검색 요청을 만들 수 있다. 데이터에 사용할 적절한 필터 조합 쿼리를 찾는데 가장 나은 방법은 시험해보는 것이다. 프로젝트 데이터에서 원하는 가장 적합한 것을 찾기 위해 여러가지 조합을 시도해보는 것이 가장 중요하다.
- 검색 요청과 검색 요청의 결과가 일반적으로 어떻게 보여질까?
- 검색 API의 주요 구성 요소 중 하나인 쿼리와 필터 DSL를 알아본다.
- 필터와 쿼리에 사용하는 가장 일반적인 방법 / 쿼리와 필터의 차이점
- 엘라스틱서치가 도큐먼트의 점수를 어떻게 계산할까?
REST API 검색 요청은 처음 접속하려고 선택한 노드에 전송되고 검색 요청을 모든 샤드(주 또는 레플리카)로 보낸다. 모든 샤드에서 정렬 및 순위를 매긴 결과로부터 충분한 정보를 수집하면, 오직 반환될 도큐먼트 내용을 담고 있는 샤드만 해당 내용을 반환하도록 요청 받는다. 이런 검색 라우팅 기능은 설정할 수 있는데, "query_then_fetch"라 부르는 기본동작이다.
엘라스틱서치 검색 요청은 JSON 도큐먼트 기반 요청이거나 URL 기반 요청이다. 요청은 서버로 보내지고, 모든 검색 요청이 같은 형식을 따르기 때문에 개별 검색 요청을 변경할 수 있는 구성 요소에 대해 이해하는 것이 도움이 된다.
색인은 두 개의 샤드이고 샤드당 한 개의 복제본으로 구성한다. 도큐먼트를 찾고 점수를 산정한 후 상위 n개의 도큐먼트가 반환된다.
(1) 검색 범위 지정하기
모든 REST 검색 요청은 _search REST 종단점을 사용하고 GET이나 POST 요청 중 하나가 된다. 전체 클러스터를 검색하거나 또는 요청 URL에 색인 이름 또는 타입을 지정해서 범위를 제한할 수 있다.
일단 색인을 하면, 다중 색인을 검색하는 alias도 사용할 수 있다. 이 방식은 접근 가능한 날짜와 시간으로 구성한 이름의 색인을 이용해서 검색할 때 종종 사용한다. 즉, logstash-yyyymmdd 형식의 색인은 하나의 앨리어스로 logstash를 호출하지만 실은 전체 색인을 가리키게 된다. 기본 검색을 할 수도 있고 curl 'localhost:9200/logstash/_search'처럼 전체 logstash 기반 색인에 한정할 수도 있다. 최고 성능을 내려면, 최소한의 색인과 타입을 사용하도록 쿼리를 제한하는 것이 좋다. 각 검색 요청이 모든 색인 샤드에 전송된다는 사실은, 더 많은 색인은 더 많은 샤드에 검색 요청이 전송된다는 것을 의미한다.
(2) 검색 요청의 기본 구성 요소
검색할 색인을 선택했다면, 검색 요청에 있어 가장 중요한 구성 요소를 설정해야 한다. 구성 요소는 반환할 도큐먼트 개수를 제어하고, 최적의 도큐먼트를 선택하게 하며, 원치 않는 도큐먼트는 결과에서 걸러내도록 한다.
- query - 검색 요청에 있어 가장 중요한 요소다. 점수 기반으로 최적의 도큐먼트를 반환하거나 원치 않는 도큐먼트를 걸러내도록 설정한다. 이 구성 요소는 DSL 쿼리와 DSL 필터를 사용해서 구성한다.
- size - 반환할 도큐먼트 개수를 의미한다.
- from - size와 함께 Pagination에 사용한다. 다음 페이지 10개를 결정하기 위해 엘라스틱서치는 상위 20개를 산출해내야 한다는 점을 기억한다. 결과 집합이 커져서 중간쯤 어딘가의 페이지를 가져오는 것은 비용이 많이 들어가는 요청이 될 것이다.
- _source - _source 필드는 어떻게 반환할 것인가를 명시한다. 기본값은 완전한 _source 필드를 반환하는 것이다. _source 설정으로 반환되는 필드를 걸러낼 수 있다. 색인된 도큐먼트가 크고 결과에서 전체 내용이 필요하지는 않을때 사용한다. 이 옵션을 사용하려면, 색인 매핑에서 _source 필드를 비활성화하지 않아야 한다. 필드와 _source간에는 차이가 있다.
- sort - 기본 정렬은 도큐먼트 점수에 따른다. 그런데, 점수 계산이 필요없거나 동일 점수의 다수 도큐먼트가 예상된다면, 반환한 도큐먼트 결과로부터 가져올때 sort를 추가해서 원하는대로 순서를 제어할 수 있다.
기본 구성 요소 중 쿼리 구성 요소에 대해 알아본다. match_all 쿼리를 match 쿼리로 변경하고, 필터 DSL에서 쿼리 DSL의 filtered 쿼리를 사용하는 검색 요청으로 변경하는 term 필터를 추가할 수 있다. 그리고 필터와 쿼리의 차이점을 깊게 알아 본다.
다음 예제는 "Hadoop" 단어를 제목으로 포함하는 그룹을 찾기 위해 match 쿼리를 사용했다.
curl 'localhost:9200/get-together/event/_search' -d '{
"query": {
"match": {
"title": "hadoop"
}
}
}'
쿼리는 3건의 이벤트를 반환한다. 쿼리를 실행해서 처음 일치하는 것의 점수를 확인한다. 첫 일치는 "Using Hadoop with Elasticsearch"라는 제목을 가진 도큐먼트이다. 이 검색을 H가 대문자인 "Hadoop" 단어로 검색하도록 변경할 수 있다. 결과는 같을 것이다.
필터가 쿼리와 유사하긴 해도 점수 매김과 여러가지 검색 기능 수행을 어떻게 적용하는지가 다르다. 쿼리가 특정 텀으로 점수 계산하는 것과 달리, 검색에서 필터는 "이 도큐먼트가 이 쿼리와 일치를 하는가"하는 단순 이진법의 예 또는 아니요 답변만을 반환한다.
필터는 이런 차이점 때문에 일반 쿼리를 사용하는 것보다 더 빠를 수 있고 캐시할 수도 있다. 필터를 이용해서 검색하는 것은 쿼리를 사용하는 일반 검색과 유사하게 보이지만, 실제는 그렇지 않다. 쿼리는 원래의 쿼리와 필터를 포함하는 "filtered" 맵으로 변경한다. 이 쿼리는 쿼리 DSL에서 filtered query로 부른다. filtered query는 두 개의 구성 요소. 즉, 쿼리와 필터를 포함한다.
$ curl 'localhost:9200/get-together/_search' -d '{
"query": {
"filtered": {
"query": {
"match": {
"title": "hadoop"
}
},
"filter": {
"term": {
"host": "andy"
}
}
}
}'
여기 "hadoop"으로 일치하는 이벤트를 위한 일반적인 쿼리처럼 필터가 사용되었으나, 필터는 "Hadoop" 단어를 위한 쿼리뿐만 아니라 특정 이벤트로 제한할 때에도 사용한다. 이 특정 필터 부분 내부에, host가 "andy"인 모든 도큐먼트를 찾기 위해 텀 필터가 사용되었다. 여기서 엘라스틱서치는 이 필터와 일치하는 도큐먼트인지 아닌지 보여주는 바이너리 비트 집합인 Bitset을 작성한다.
엘라스틱서치가 비트셋을 만들고 나서는 도큐먼트를 필터링하는데 사용할 수는 있으나 검색의 쿼리 일부분으로 검색하는 것은 아니다. 필터는 점수 계산이 필요한 도큐먼트를 제한한다. 제한된 도큐먼트 집합의 접수는 쿼리 기반으로 계산된다. 이런 이유로, 필터를 추가하는 것은 전체 쿼리를 단일 검색으로 결합하는 것보다 더 빠른다. 어떤 종류의 필터인가에 따라 엘라스틱서치는 비트셋 결과를 캐시할 수 있다. 필터를 다른 검색에 사용해도 비트셋을 다시 계산할 필요가 없다.
그러나 어떤 유형의 필터의 경우, 엘라스틱서치가 다시 사용되지 않을 것으로 판단하거나 비트셋 재생성 비용이 사소하다면 자동으로 캐시하지 않을 수 있다. 캐시하기 어려운 쿼리의 예로 최근 한 시간의 모든 문서로 결과를 제한하는 필터의 경우가 그러하다. 이 쿼리는 이를 실행할 때 매초 변경되어야 하므로 캐시할 이유가 없다. 추가로, 엘라스틱서치는 필터를 캐시해야 할지에 관해 수동으로 지정하는 기능을 제공한다. 이 모든 것은 필터를 가진 검색을 더 빠르게 만든다. 그러므로 가능하다면 쿼리의 일부분을 필터로 만들 필요가 있다.
비록 엘라스틱서치에서 쿼리하는 수많은 방법이 있지만, 어떤 쿼리는 색인에 데이터가 어떻게 저장되었는지에 의존하는 쿼리보다 더 나을 수 있다. 엘라스틱서치가 지원하는 쿼리의 서로 다른 타입을 알아보고, 쿼리에서 어떻게 사용하는지 알아보도록 하겠다. 어떤 쿼리가 데이터에 가장 적합한지 결정할 수 있도록 각각 성능에 대해서도 언급하고, 각 쿼리를 사용할 때의 장단점에 대해서 가늠해보도록 한다.
전체 도큐먼트를 반환하는 match_all 쿼리로 시작하여, 특정 필드에 대해 일치하는 다어로 결과를 제한하는 match 쿼리로, 그리고 특정 필드에 있는 텀을 사용해서 결과를 제한하는 텀 필터가지 사용해봤다. 그리고 query_string을 사용하는 방법도 존재한다. 이 쿼리는 URL 기반 검색에서 사용하게 된다.
MATCH_ALL 쿼리
이 필터는 모든 도큐먼트를 일치하게 한다. 도큐먼트 점수에 관해 신경쓰지 않을때라면, 쿼리 대신 필터 사용이 필요할때 match_all 쿼리가 상당히 유용하다. 또는 검색하는 색인과 타입 사이에서 모든 도큐먼트를 반환하고 싶을때 유용하다. 이 쿼리는 다음과 같은 형태다.
curl 'localhost:9200/_search' -d '{
"query" : {
"match_all": {}
}
}'
검색에 쿼리 부분 대신 필터를 사용하면 쿼리는 아래와 같다.
curl 'localhost:9200/get-together/_search' -d '{
"query": {
"filtered": {
"query": {
"match_all": {}
},
"filter": {
... 필터 세부 내용 ...
}
}
}
}'
거의 모든 것을 검색하기 때문에 검색엔진을 사용함에도 사용자에게는 유용해 보인다. Match_all 쿼리를 기본으로 사용하면 검색요청도 더 쉽게 만들 수 있다. 그러므로 쿼리 요소는 이 경우 완벽하게 생략할 수 있다.
QUERY_STRING 쿼리
엘라스틱서치 서버를 시작하고 실행할때, query_string 쿼리를 이용하면 쉽게 쿼리 결과를 얻을 수 있다. query_string 검색은 요청 URL로부터 또는 요청 본문을 전송하는 것으로부터 수행할 수 있다. 아래 예제는 "nosql"을 포함하는 도큐먼트를 검색하는데, 이 쿼리는 도큐먼트 한 건을 반환할 것이다.
// query_string 검색은 URL 파라미터처럼 전송
curl -X GET 'localhost:9200/get-together/_search?q=nosql&pretty'
// 같은 query_string 검색을 요청 본문처럼 전송
curl -X POST 'http://localhost:9200/get-together/_search?pretty' -d '{
"query": {
"query_string" : {
"query" : "nosql"
}
}
}'
기본적으로, query_string 쿼리는 _all 필드를 검색한다. _all 필드는 모든 필드 결합으로 구성되어 있다. description:nosql 처럼 쿼리로 특정 필드를 지정하거나 요청 본문에 default_field를 지정하면 이를 변경할 수 있다.
curl -X POST 'localhost:9200/_search' -d '{
"query": {
"query_string" : {
// 쿼리에 지정된 필드가 없기 때문에 기본 필드가 사용.
"default_field": "description",
"query": "nosql"
}
}
}'
추측할 수 있듯이, 이 문법은 단일 단어를 검색하는 것보다 더 많은 것을 제공한다. 내부적으로, 이는 모두 AND와 OR처럼 boolean 연산자로 서로 다른 텀을 검색하고 추가적으로 마이너스(-) 연산을 사용해서 결과로부터 도큐먼트를 제외하는 결합의 루씬 쿼리 문법이다. 다음 쿼리는 "nosql" 이름으로 모든 그룹을 검색하지만 description에 "mongodb"를 포함하지 않는다.
name:nosql AND -description:mongodb
1999년부터 2001년 사이에 생성한 모든 search와 모든 lucene 그룹은 다음과 같이 검색할 수 있다.
(tags:search OR tags:lucene) AND created_on:[1999-01-01 TO 2001-01-01]
query_string는 쿼리가 위력적이여서, 웹사이트 사용자에게 그대로 노출하면, 엘라스틱서치 클러스터가 위험할 수 있다. 사용자가 잘못된 형식으로 쿼리를 실행하면 예외 상황에 맞닥뜨리게 될 수 있다. 또한, 모든 것을 반환하는 조합을 만들 가능성도 있어서, 이는 클러스터에 리스크가 될 수 있다.
도큐먼트의 필드와 필드 내에 있는 문자열 검색을 허용하는 term, terms, match, multi_match 쿼리를 포함하는 query_string 쿼리는 다른 대체재로 교체하는 것을 추천한다. 적절한 대체재는 simple-query-string 쿼리인데, +,-,AND,OR를 사용하여 쉽게 접근 가능한 쿼리 문법으로 교체할 수 있다.
텀 쿼리와 텀 필터
텀 쿼리와 필터는 실행 가능한 가장 단순한 쿼리인데, 필드와 텀을 지정해서 도큐먼트 내에서 검색할 수 있다. 검색한 텀이 분석되지 않았기 때문에 완전히 일치하는 도큐먼트 결과만 찾는것은 것을 알아둔다. 엘라스틱서치에 의해 어떻게 텍스트를 개별적인 색인 조각으로 토큰을 만드는 지는 데이터 분석 파트에서 확인할 수 있다. 루씬에 익숙하다면, 텀쿼리가 직접적으로 루씬 TermQuery로 매핑된다는 것은 유용한 정보가 된다.
다음은 elasticsearch 태그로 그룹을 검색하는 텀 쿼리이다.
curl 'localhost:9200/get-together/group/_search' -d '{
"query": {
"term": {
"tags": "elasticsearch"
}
},
"_source": ["name", "tags"]
}'
{
...
"hits": [
{
"_id": "3",
"_index": "get-together",
"_score": 1.0769258,
"_type": "group",
"_source": {
"name": "Elasticsearch San Francisco",
"tags": [
"elasticsearch",
"big data",
"lucene",
"open source"
]
}
},
{
"_id": "2",
"_index": "get-together",
"_score": 0.8948604,
"_type": "group",
"_source": {
"name": "Elasticsearch Denver",
"tags": [
"denver",
"elasticsearch",
"big data",
"lucene",
"solr"
]
}
}
],
...
}
텀 쿼리처럼 텀 필터는 점수에 영향을 미치지 않고 텀을 포함하는 도큐먼트의 제한된 결과가 필요할 때 사용할 수 있다. 점수를 사용한 이전 예제의 도큐먼트 점수를 다음 예제와 비교하자. 필터가 계산에 방해가 되지도 점수에 영향을 미치지도 않는다는 것을 알게 될 것이다. Match_all 쿼리 대문에 모든 도큐먼트의 점수는 1.0이 된다. 도큐먼트 점수는 필터가 쿼리대신 사용되었으므로 이제 상수가 된다.
curl 'localhost:9200/get-together/group/_search' -d '{
"query": {
"filtered": {
"match_all": {}
},
"filter": {
"term": {
"tags": "elasticsearch"
}
}
},
"_source": ["name", "tags"]
}'
{
...
"hits": [
{
"_id": "3",
"_index": "get-together",
"_score": 1.0,
"_type": "group",
"_source": {
"name": "Elasticsearch San Francisco",
"tags": [
"elasticsearch",
"big data",
"lucene",
"open source"
]
}
},
{
"_id": "2",
"_index": "get-together",
"_score": 1.0,
"_type": "group",
"_source": {
"name": "Elasticsearch Denver",
"tags": [
"denver",
"elasticsearch",
"big data",
"lucene",
"solr"
]
}
}
],
...
}
텀즈 쿼리
텀 쿼리와 유사하게, 텀즈(term이 아닌 terms) 쿼리로 도큐먼트 필드에서 다중 텀으로 검색할 수 있다. 예를 들어, 다음 예제는 "jvm", "hadoop" 중 어느 하나와 일치하는 태그의 그룹을 검색한다.
curl 'localhost:9200/get-together/group/_search' -d '{
"query": {
"terms": {
"tags": ["jvm", "hadoop"]
}
},
"_source": ["name", "tags"]
}'
{
...
"hits": [
{
"_id": "1",
"_index": "get-together",
"_score": 0.33779633,
"_type": "group",
"_source": {
"name": "Denver Clojure",
"tags": [
"clojure",
"denver",
"function programming",
"jvm",
"java"
]
}
},
{
"_id": "4",
"_index": "get-together",
"_score": 0.22838624,
"_type": "group",
"_source": {
"name": "Boulder/Denver big data get-together",
"tags": [
"big data",
"data visualization",
"open source",
"cloud computing",
"hadoop"
]
}
}
]
}
쿼리 일치 전에 도큐먼트에서 최소 개수의 텀 일치를 강제하려면, minimum_should_match 파라미터를 지정한다. 이외에 다중 쿼리와 단일 쿼리를 결합할 필요가 있을때, 다중 텀 쿼리를 결합한 복합 쿼리를 작성할 수도 있다.
curl 'localhost:9200/get-together/group/_search' -d '{
"query": {
"terms": {
"tags": ["jvm", "hadoop", "lucene"],
"minimum_should_match": 2
}
}
}'
매치 쿼리와 텀 필터
텀 쿼리와 유사하게 매치 쿼리는 검색하려는 필드와 검색하려는 문자열을 포함하는 해시맵인데, 필드나 한번에 모든 필드를 검색하는 _all 필드가 올 수 있다. 다음 예제는 name 필드에 "elasticsearch"를 포함하는 그룹을 검색하는 매치 쿼리다.
curl 'localhost:9200/get-together/group/_search' -d '{
"query": {
"match": {
"name": "elasticsearch"
}
}
}'
매치 쿼리는 몇몇 서로 다른 방식으로 동작할 수 있다. 가장 주요한 두 가지의 기능은 boolean과 phrase다.
(1) BOOLEAN 쿼리
기본적으로, 쿼리 매치는 Boolean 기능과 OR 연산을 사용한다. 예를 들어 "Elasticsearch Denver" 텍스트를 검색한다면 엘라스틱서치는 "Elasticsearch OR Denver"로 검색해서 "Elasticsearch Amsterdam"과 "Denver Clojure Group" 모두로부터 get-together groups가 일치할 것이다.
"Elasticsearch"와 "Denver"를 모두 포함하는 결과를 검색하려면, 맵과 추가하는 연산자 필드 설정에 들어가는 일치 필드 이름을 수정하면서 연산자를 변경한다.
curl 'localhost:9200/get-together/_search' -d '{
"query": {
"match": {
"name": {
"query": "Elasticsearch Denver",
"operator": "and"
}
}
}
}'
(2) PHRASE 쿼리
도큐먼트 내에서 각 단어의 위치에 따른 leeway 값처럼 특정 구를 검색할때 phrase 쿼리가 유용하다. Leeway는 slop으로 불리는데 구문 내에서 토큰 사이의 거리를 표현하는 수치 값이다. get-together의 그룹 name을 기억해 내려 할때, "Enterprise" 단어와 "London" 단어는 기억하나 name의 나머지는 기억하지 못한다고 하자. "enterprise london" 구문을 기본값 0 대신 slop을 1 또는 2로 설정해서 완전한 그룹 제목을 몰라도 구문을 포함하는 결과를 찾아 검색할 수 있다.
curl 'localhost:9200/get-together/group/_search' -d '{
"query": {
"match": {
"name": {
"type": "phrase" // 일반 match 쿼리 대신 match phrase 쿼리 사용
"query": "enterprise london",
"slop": 1 // slop에 1을 지정해서 텀간 leeway 거리를 가지도록.
}
}
}
}'
Phrase_prefix 쿼리
Match_phrase 쿼리와 유사하게 match_phrase_prefix 쿼리는 phrase로 검색하는 것에 더해서 phrase 내에서 마지막 텀에 프리픽스 매칭을 허용한다. 이 기능은 검색을 제안하는 검색창에서 사용자가 검색 텀을 입력하는 동안 자동완성을 제공하는 데 정말 유용하다. 이런 유형의 기능으로 검색을 사용할 때, max_expansions 설정을 사용해서, 검색이 반환할 이해 가능한 수준의 총 소요 시간 내에서 확장할 프리픽스의 최댓값을 설정하는 것이 좋다.
curl 'localhost:9200/get-together/group/_search' -d '{
"query": {
"match": {
"name": {
"type": "phrase_prefix",
"query": "Elasticsearch den",
"max_expansions": 1
}
}
},
"_source": ["name"]
}'
Boolean과 phrase 쿼리는 사용자 입력을 받아들이는 데 훌륭한 선택이 된다. Query_string 쿼리와 다르게 매치 쿼리가 +,-,ㅡ?,! 같은 예약된 문자를 막지 않으면서 오류 발생이 가장 적은 방식으로 사용자 입력을 그대로 넘기도록 허용하기 때문이다.
(1) MULTI_MATCH로 다중 필드 일치
비록 multi_match 쿼리가 텀즈 쿼리처럼 필드에서 다중 일치로 검색하는 기능으로 고려해볼 수 있겠지만, 이 기능은 다소 다르다. 다만, 다중 필드의 값을 검색하도록 허용한다. 이는 get-together 예제에서 그룹 name과 description 문자열로 검색하기를 원하는 곳에 유용할 수 있다.
curl 'localhost:9200/get-together/_search' -d '{
"query": {
"multi_match": {
"query": "elasticsearch hadoop",
"fields": ["name", "description"]
}
}
}'
매치 쿼리가 phrase 쿼리, prefix 쿼리 또는 phrase_prefix 쿼리로 전환할 수 있는 것처럼, multi_match 쿼리는 type 키를 추가해서 phrase 쿼리 또는 phrase_prefix 쿼리로 전환할 수 있다. Multi_match 쿼리는 검색을 위해 단일 필드 대신 다중 필드를 지정할 수 있다는 것을 제외하고는 매치 쿼리와 완전히 비슷하다.
매치 쿼리를 사용하면 어떠한 것도 검색할 수 있는데, 이는 대부분의 경우 기본적으로 사용할 수 있는 쿼리 타입이라 할 수 있어, 가능한 이를 사용하도록 강하게 추천한다.
bool 쿼리
Bool 쿼리는 몇 개의 쿼리라도 특정 부분이 must, should, must_not로 데이터가 일치하는지 명시하게 하는 쿼리 구문을 이용해서 단일 쿼리에 결합할 수 있다.
- bool 쿼리로 must 매치를 지정한다면, 쿼리가 반환하는 오직 일치하는 결과만 받는다.
- should 매치를 지정하면, 도큐먼트가 반환하는 특정 개수의 구문이 일치해야 한다는 의미다.
- must 구문이 지정되지 않으면, 도큐먼트로부터 반환되는 것으로부터 일치하는 적어도 하나는 가져야 한다.
- 마지막으로 must_not 구문은 일치하는 도큐먼트가 결과셋에서 제외하는데 사용한다.
bool 쿼리 절 | 이진 연산 대응 | 의미 |
must | 다중 절을 결합하기 위해 이진 and 연산을 사용 (query1 AND query2 AND query3) | must 절에서 검색은 도큐먼트가 일치해야 한다. 소문자 and는 함수이고, 대문자 AND는 연산자이다. |
must_not | 이진 not 연산으로 다중 절 결합 | must_not 절에서 검색은 도큐먼트의 부분이 되지 않아야 한다. 다중 절은 이진 not 메소드에서 결합한다. |
should | 이진 or 연산으로 다중 절 결합 | should 절에서 검색은 이진 OR(query1 OR query2 OR query3)와 유사하게 도큐먼트가 일치하거나 그렇지 않을 수 있다. 그러나 최소 minimum_should_match 파라미터로 이 갯수만큼을 일치해야 한다. (must가 존재하지 않으면 기본값은 1이고, must가 존재한다면 0이다) |
David가 참성한(attendees 텀) 이벤트를 검색하는데, Clint나 Andy 중 하나는 참석해야 하고, June 30, 2013보다 오래되지 않아야 한다.
curl 'localhost:9200/get-together/_search' -d '{
"query": {
"bool": {
"must": [
{
"term": {
"attendees": "david"
}
}
],
"should": [
{
"term": {
"attendees": "clint"
}
},
{
"term": {
"attendees": "andy"
}
}
],
"must_not": [
{
"range": {
"date": {
"lt": "2013-06-30T00:00"
}
}
}
],
"minimum_sould_match": 1
}
}
}'
bool 필터
Bool 쿼리의 필터 버전은 쿼리 버전처럼 거의 동일한 역할을 하지만, 쿼리 대신 필터를 결합한다. 이전 예제의 필터에 해당하는 것은 다음과 같다. 단, bool 필터는 minimum_sould_match 속성을 제공하지 않는다.
curl 'localhost:9200/get-together/_search' -d '{
"query": {
"filtered": {
"query": {
"match_all": {}
},
"filter": {
"bool": {
"must": [
{
"term": {
"attendees": "david"
}
}
],
"should": [
{
"term": {
"attendees": "clint"
}
},
{
"term": {
"attendees": "andy"
}
}
],
"must_not": [
{
"range": {
"date": {
"lt": "2013-06-30T00:00"
}
}
}
]
}
}
}
}
}'
query_string과 매치 쿼리같은 범용 쿼리는 검색차에서 사용자가 입력한 단어로 그런 쿼리를 실행할 수 있어서 특히 유용하다. 검색 범위를 좁히는 목적으로 특정 사용자 인터페이스는 검색창 옆에 최근 생성된 그룹을 검색하도록 하는 달력 위젯이나 특정 위치에서 발생한 이벤트를 필터링하려는 체크 상자 같은 또 다른 요소를 포함하기도 한다.
(1) 범위 쿼리와 필터
특정 범위 사이의 숫자, 날짜 및 문자열까지고 사용할 수 이쓴 값으로 쿼리하는 데 사용한다. 범위 쿼리를 사용해서 필드의 상위 및 하위 값을 지정한다.
curl 'localhost:9200/get-together/_search' -d '{
"query": {
"range": {
"created_on": {
"gt": "2012-06-01",
"lt": "2012-09-01"
}
}
}
}'
curl 'localhost:9200/get-together/_search' -d '{
"query": {
"filtered": {
"query": {
"match_all": {}
}
},
"filter": {
"range": {
"created_on": {
"gt": "2012-06-01",
"lt": "2012-09-01"
}
}
}
}
}'
범위 쿼리는 문자열 범위도 지원한다. 범위 검색을 사용할 때 필터가 더 나은 선택인지 신중하게 생각하는게 좋다. 바이너리 매치를 가지는 범위 쿼리로 들어간 도큐먼트는 범위 쿼리가 되는데 필요하지 않기 때문이다. 쿼리로 만들지 필터로 만들지 확실치 않다면 필터로 만드는 것을 권장한다. 범위 쿼리를 만드는데 99% 경우, 필터가 옳은 선택이다.
프리픽스 쿼리와 필터
텀 쿼리와 유사하게 프리픽스 쿼리와 필터는 검색하기 전에 분석이 안된 프리픽스를 포함하는 텀을 검색하도록 해준다. 예를 들어, "liber"로 시작하는 모든 이벤트의 색인 검색은 다음 쿼리를 사용한다.
curl 'localhost:9200/get-together/event/_search' -d '{
"query": {
"prefix": {
"title": "liber"
}
}
}'
curl 'localhost:9200/get-together/event/_search' -d '{
"query": {
"filtered": {
"query" : {
"match_all": {}
},
"filter": {
"prefix": {
"title": "liber"
}
}
}
}
}'
검색 프리픽스는 전송 전에는 분석되지 않으므로, "liber"를 "Liber"로 변경하여 검색요청을 보내면 색인에 소문자로 된 텀을 찾을 수 없다. 이는 엘라스틱서치가 도큐먼트를 분석하고 쿼리하는 방식때문이다. 이 기능때문에 프리픽스 쿼리는 텀이 색인의 일부분일때 사용자가 입력한 부분 텀의 자동완선에 있어서 좋은 선택이다. 예를 들어, 존재하는 카테고리가 이미 알려져 있을때 카테고리 입력창을 제공할 수있다. 사용자가 색인의 일부분인 텀을 입력하고 있다면, 사용자의 검색창에 입력하는 텍스트를 소문자로 변경한 다음 결과를 보여주는 어떤 다른 결과를 보여주기 위해 프리픽스 쿼리를 사용할 수 있다.
프리픽스 쿼리로부터 매칭 결과를 가지고 있을때 사용자가 입력하는 도중에 제안처럼 그들을 제공할 수 있다. 그러나 결과에서 텀을 분석하거나 fuzziness 값을 지정하기를 원하다면, 자동완성 기능을 위해 match_phrase_prefix 쿼리를 사용하는 게 아마 나을 것이다.
출처: https://12bme.tistory.com/477?category=737765 [길은 가면, 뒤에 있다.]
'Big Data > 빅데이터' 카테고리의 다른 글
[엘라스틱서치] Elasticsearch in action 정리(6) - 성능 극대화 (0) | 2020.08.03 |
---|---|
[엘라스틱서치] Elasticsearch in action 정리(5) - 집계 데이터 (0) | 2020.08.03 |
[엘라스틱서치] Elasticsearch in action 정리(4) - 유사도 검색 (0) | 2020.08.03 |
[엘라스틱서치] Elasticsearch in action 정리(3) - 데이터 분석 (0) | 2020.08.03 |
[데이터처리] 로그데이터 다루기(2) - 수집 미들웨어 Fluentd란? (0) | 2020.08.03 |
[데이터처리] 로그 데이터 다루기 (1) - 수집 미들웨어 Fluentd 중심 (0) | 2020.08.03 |
[엘라스틱서치] Elasticsearch in action 정리(1) (0) | 2020.08.03 |
[대용량데이터] 대용량 처리 컨셉 오버뷰 (0) | 2020.08.03 |