# 4.4 검색 API - \_search API

&#x20; 지금까지는 도큐먼트 단위의 입력, 수정, 삭제, 조회 하는 방법을 알아보았습니다. 하지만 Elasticsearch의 진가는 쿼리를 통한 검색 기능에 있습니다. 검색은 인덱스 단위로 이루어집니다. `GET <인덱스명>/_search` 형식으로 사용하며 쿼리를 입력하지 않으면 전체 도큐먼트를 찾는 **match\_all** 검색을 합니다.

### URI 검색

&#x20; \_search 뒤에 `q` 파라메터를 사용해서 검색어를 입력할 수 있습니다. 이렇게 요청 주소에 검색어를 넣어 검색하는 방식을 **URI 검색**이라고 합니다.

&#x20; 앞에서 만든 test 인덱스에서 **"value"** 라는 값을 검색하기 위해서는 다음과 같이 입력합니다.

{% tabs %}
{% tab title="request" %}
{% code title="URI 검색으로 검색어 "value" 검색" %}

```javascript
GET test/_search?q=value
```

{% endcode %}
{% endtab %}

{% tab title="response" %}
{% code title="URI 검색으로 검색어 "value" 검색 결과" %}

```javascript
{
  "took" : 3,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 0.105360515,
    "hits" : [
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 0.105360515,
        "_source" : {
          "field" : "value three"
        }
      },
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.105360515,
        "_source" : {
          "field" : "value two"
        }
      }
    ]
  }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

&#x20; 결과를 보면 `hits.total.value` 부분에 검색 결과 전체에 해당되는 문서의 개수가 표시되고 다시 그 안의 `hits:[ ]` 구문 안에 배열로 가장 정확도가 높은 문서 10개가 나타납니다. 이 정확도를 **relevancy**(렐러번시 라고 읽습니다) 라고 하며 뒤에서 다시 설명하도록 하겠습니다.

&#x20; 두 개의 검색어 **"value"** 그리고 **"three"** 를 **AND** 조건으로 검색 하려면 다음과 같이 입력합니다. URI 쿼리에서는 `AND`, `OR`, `NOT` 의 사용이 가능하며 반드시 모두 대문자로 입력해야합니다.

{% tabs %}
{% tab title="request" %}
{% code title="URI 검색으로 검색어 "value AND three" 검색" %}

```javascript
GET test/_search?q=value AND three
```

{% endcode %}
{% endtab %}

{% tab title="response" %}
{% code title="URI 검색으로 검색어 "value AND three" 검색 결과" %}

```javascript
{
  "took" : 3,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 0.87546873,
    "hits" : [
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 0.87546873,
        "_source" : {
          "field" : "value three"
        }
      }
    ]
  }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

&#x20; **value** 와 **three** 를 모두 포함한 `test/_doc/3` 도큐먼트 만이 결과로 리턴되었습니다. 검색어 value 을 field 필드에서 찾고 싶으면 다음과 같이 `<필드명>:<검색어>` 형태로 입력합니다. 검색은 항상 필드를 지정해서 하는 것이 좋습니다.

{% tabs %}
{% tab title="request" %}
{% code title="URI 검색으로 "field" 필드에서 검색어 "value" 검색" %}

```javascript
GET test/_search?q=field:value
```

{% endcode %}
{% endtab %}

{% tab title="response" %}
{% code title="URI 검색으로 "field" 필드에서 검색어 "value" 검색 결과" %}

```javascript
{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 0.18232156,
    "hits" : [
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 0.18232156,
        "_source" : {
          "field" : "value three"
        }
      },
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.18232156,
        "_source" : {
          "field" : "value two"
        }
      }
    ]
  }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

&#x20; URI 검색은 루씬의 기본 쿼리 문법을 사용하며 손쉽게 다룰 수 있습니다. 또한 웹 브라우저 주소창 등에서도 사용 가능하기 때문에 빠르게 쓰긴 쉬우나 좀 더 복잡한 검색을 위해서는 다음에 설명하는 데이터 본문(data body) 검색을 이용해야 합니다.

### 데이터 본문 (Data Body) 검색

&#x20; **데이터 본문(data body) 검색**은 검색 쿼리를 데이터 본문으로 입력하는 방식입니다. Elasticsearch의 QueryDSL을 사용하며 쿼리 또한 Json 형식으로 되어 있습니다. 처음 익힐때는 다소 복잡 해 보일 수 있으나 주로 사용하는 쿼리 몇가지들 부터 차근 차근 익혀나가면 크게 어렵지 않게 사용이 가능합니다.

&#x20; 가장 쉽고 많이 사용되는 것은 **match** 쿼리입니다. 여기서는 문법만 살펴보고 다음 검색 장에서 더 많은 쿼리들에 대해 자세히 다뤄보도록 하겠습니다. 데이터 본문 검색으로 field 필드값이 value 인 도큐먼트를 검색하기 위해서는 다음 명령을 실행합니다.

{% tabs %}
{% tab title="request" %}
{% code title="데이터 본문 검색으로 "field" 필드에서 검색어 "value" 검색" %}

```javascript
GET test/_search
{
  "query": {
    "match": {
      "field": "value"
    }
  }
}
```

{% endcode %}
{% endtab %}

{% tab title="response" %}
{% code title="데이터 본문 검색으로 "field" 필드에서 검색어 "value" 검색 결과" %}

```javascript
{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : 0.105360515,
    "hits" : [
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 0.105360515,
        "_source" : {
          "field" : "value three"
        }
      },
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.105360515,
        "_source" : {
          "field" : "value two"
        }
      }
    ]
  }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}

&#x20; 쿼리 입력은 항상 `query` 지정자로 시작합니다. 그 다음 레벨에서 쿼리의 종류를 지정하는데 위에서는 **match** 쿼리를 지정했습니다. 그 다음은 사용할 쿼리 별로 문법이 상이할 수 있는데 match 쿼리는 `<필드명>:<검색어>` 방식으로 입력합니다.

### 멀티테넌시 (Multitenancy)

&#x20; Elasticsearch는 여러 개의 인덱스를 한꺼번에 묶어서 검색할 수 있는 **멀티테넌시**를 지원합니다.`logs-2018-01`, `logs-2018-02` … 와 같이 날짜별로 저장된 인덱스들이 있다면 이 인덱스들을 모두 **`logs-*/_search`** 명령으로 한꺼번에 검색이 가능합니다. 특히 시간순으로 따라 쌓이는 로그 데이터를 다룰 때는 인덱스를 일단위 등으로 구분하는것이 좋습니다. 나중에 필드 구조가 변경되거나 크기가 커져서 샤드 설정을 변경하거나 할 때 더욱 용이합니다.

&#x20; 여러 인덱스를 검색할때는 쉼표`,` 로 나열하거나 와일드카드 `*` 문자로 묶을 수 있습니다.

{% code title="쉼표로 나열해서 여러 인덱스 검색" %}

```javascript
GET logs-2018-01,2018-02,2018-03/_search
```

{% endcode %}

{% code title="와일드카드 \* 를 이용해서 여러 인덱스 검색" %}

```javascript
GET logs-2018-*/_search
```

{% endcode %}

{% hint style="danger" %}
인덱스명 대신 `_all` 지정자를 사용하여 `GET _all/_search` 와 같이 실행하면 클러스터에 있는 모든 인덱스를 대상으로 검색이 가능합니다. 하지만 `_all`은 시스템 사용을 위한 인덱스 같은 곳의 데이터까지 접근하여 불필요한 작업 부하를 초래하므로 `_all` 은 되도록 사용하지 않도록 합니다.
{% endhint %}
