Software Workshop

기본 정보

클러스터 상태 확인

클러스터의 건강 상태를 확인해보자. 다음 API의 응답 중에서 status 필드의 값이 중요하다.

curl localhost:9200/_cluster/health
{
  "cluster_name": "opensearch_homebrew",
  "status": "green",
  "timed_out": false,
  "number_of_nodes": 3,
  "number_of_data_nodes": 3,
  "discovered_master": true,
  "discovered_cluster_manager": true,
  "active_primary_shards": 0,
  "active_shards": 0,
  "relocating_shards": 0,
  "initializing_shards": 0,
  "unassigned_shards": 0,
  "delayed_unassigned_shards": 0,
  "number_of_pending_tasks": 0,
  "number_of_in_flight_fetch": 0,
  "task_max_waiting_in_queue_millis": 0,
  "active_shards_percent_as_number": 100.0
}

기존 인덱스 정보 확인

이미 생성되어 있는 index 목록을 조회하는 것도 필요하다.

curl localhost:9200/_cat/indices

다음과 같이 index별 상태를 확인할 수 있다.

green open test_index -pyXIxp3R4CsT_5yiB11qw 1 3 401 0 23.1kb 23.1kb
yellow open ebooks -pyXQ51ax1ctt_29flzj2m 1 3 598 0 30.5kb 30.5kb

문서 데이터 적재

이제부터는 특정 인덱스 "test_index"에 저장하는 것을 전제로 하겠다.

POST method로 임의의 json 문서를 insert할 수 있다.

curl -s -X POST  localhost:9200/test_index/_doc -H "Content-Type: application/json" -d '{"num": 30}'

Bash의 while loop를 이용하여 1000건 insert하는 예제는 다음과 같다.

total_count=1000
i=0
while [ "$i" -lt "$total_count" ]; do
    echo -n "."

    curl -s -X POST  localhost:9200/test_index/_doc -H "Content-Type: application/json" -d '{"num": '"$i"'}' > /dev\
/null
    i=$((i+1))
done

_doc API에 접근하여 POST method로 다음과 같은 json 문서 데이터를 insert한다.

{ "num": 1 }

한 건씩 적재하면 성능 상 손해가 생기는데, 이 문제를 해결하는 방법으로 bulk API를 사용하면 된다. (다른 문서 curl을_이용한_ElasticSearch_bulk_API_사용 에서 자세히 다루고 있다.)
이 코드 예제는 0부터 999까지의 num 값을 가지는 문서를 Bash의 while loop를 이용하여 반복해서 insert하고 있다.

문서 건수 확인

curl -s localhost:9200/test_index/_count

_count API를 이용하여 test_index에 저장되어 있는 문서의 갯수를 확인할 수 있다. 그러나 많은 문서를 빠른 속도로 insert한 직후에 바로 count를 조회하면 정확한 값이 조회되지 않는다. 이럴 경우에 _refresh API를 이용하여 문서의 메타데이터/통계를 갱신해줄 필요가 있다.

curl -s localhost:9200/test_index/_refresh
curl -s localhost:9200/test_index/_count

검색 (pagination)

단순히 문서를 조회할 때는 _doc API를 이용해도 되지만

curl -s localhost:9200/test_index/_doc/gwbBCIgBbIjXWaPdciBv

id를 미리 정의해서 등록해두었고 그걸 확인할 수 있을 때만 가능하다.

일반적인 검색은 조건에 일치하는 문서들을 일부 검색한 다음에, pagination을 통해서 조금씩 더 조회하는 절차를 따르는데, ElasticSearch에서는 이 기능을 scroll이라고 한다. 다음과 같이 scroll을 이용할 수 있다.

  1. 최초 검색하면서 scroll 기능을 사용하겠다고 선언하고 page size를 정한다. 응답으로 scroll id를 받는다.
  2. 이후의 검색은 그 scroll id를 가지고 반복적으로 호출하면 된다.
  3. scroll을 이용한 검색의 응답에 대해서 error가 발생했는지, 검색된 결과가 0건보다 많은지를 확인할 필요가 있다.

최초 검색

100건씩 1분짜리 세션을 지정해서 모든 문서를 조회하는 요청은 다음과 같다. 1h로 해도 된다.

curl -s localhost:9200/test_index/_search\?scroll=1m -H 'Content-Type: application/json' -d '{"size": 100, "query": {"match_all": {} } }'

응답에서 scroll id를 얻어야 한다.

curl -s localhost:9200/test_index/_search\?scroll=1m -H 'Content-Type: application/json' -d '{"size": 100, "query": {"match_all": {} } }' | jq -r ._scroll_id

jq 명령을 추가로 설치할 필요가 있다.

scroll id는 FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFmdVRksxd0VMUUhteEl5SWxCSWxhQWcAAAAAAATk3RZDMFVpdWZUQVNhdXRKaVhpTEdRYkVB로 확인되었다.

연속 검색

curl -s localhost:9200/_search/scroll -H 'Content-Type: application/json' -d '{"scroll": "1m", "scroll_id": "FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFmdVRksxd0VMUUhteEl5SWxCSWxhQWcAAAAAAATk3RZDMFVpdWZUQVNhdXRKaVhpTEdRYkVB"}'

이 요청의 응답에 대해서 error가 발생하는지, 검색결과 문서 리스트가 비어있진 않은지 확인할 필요가 있다.

Bash의 while loop를 이용해서 반복적으로 검색해보자.

page_size=100
while :; do
    result=$(curl -s localhost:9200/_search/scroll -H 'Content-Type: application/json' -d '{"scroll": "1m", "scroll\
_id": "'"$scroll_id"'"}')
    if echo "$result" | grep -q "error"; then
        echo "error in scrolling"
        break;
    fi

    count=$(echo "$result" | jq -r ".hits.hits | length")
    if [ "$count" -gt 0 ]; then
        echo -n "."
    else
        echo; echo "end of searching"
        break
    fi
done

Troubleshooting

기존 데이터 삭제

curl -s -X DELETE localhost:9200/test_index

기존 scroll 삭제

curl -s -X DELETE localhost:9200/_search/scroll -H 'Content-Type: application/json' -d '{ "scroll_id": "FGluY2x1ZGVfY29udGV4dF91dWlkDXF1ZXJ5QW5kRmV0Y2gBFmdVRksxd0VMUUhteEl5SWxCSWxhQWcAAAAAAATk3RZDMFVpdWZUQVNhdXRKaVhpTEdRYkVB" }'

완성 버전

#!/bin/bash

total_count=2000
page_size=100

date

echo; echo "removing..."
if curl -s -X DELETE localhost:9200/test_index > /dev/null; then
    echo "success in deleting data"
else
    echo "error in deleting data"
    exit 1
fi

date

echo; echo "loading..."
i=0
while [ "$i" -lt "$total_count" ]; do
    echo -n "."

    curl -s -X POST  localhost:9200/test_index/_doc -H "Content-Type: application/json" -d '{"num": '"$i"'}' > /dev/null
    i=$((i+1))
done
echo
echo "$i"

curl -s localhost:9200/test_index/_refresh
curl -s localhost:9200/test_index/_count

date

echo; echo "removing old scroll cursor..."
scroll_id=$(cat scroll_id.txt)
echo "$scroll_id"

curl -s -X DELETE localhost:9200/_search/scroll -H 'Content-Type: application/json' -d '{ "scroll_id": "'"$scroll_id"'" }' | jq .

echo; echo "searching and getting scroll cursor..."
scroll_id=$(curl -s localhost:9200/test_index/_search\?scroll=1m -H 'Content-Type: application/json' -d '{"size": '"$page_size"', "query": {"match_all": {} } }' | jq -r ._scroll_id)
echo "$scroll_id"
echo "$scroll_id" > scroll_id.txt

echo; echo "searching (with pagination)..."
while :; do
    result=$(curl -s localhost:9200/_search/scroll -H 'Content-Type: application/json' -d '{"scroll": "1m", "scroll_id": "'"$scroll_id"'"}')
    #echo "$result"
    if echo "$result" | grep -q "error"; then
        echo "error in scrolling"
        break;
    fi

    count=$(echo "$result" | jq -r ".hits.hits | length")
    #echo "$count"
    if [ "$count" -gt 0 ]; then
        echo -n "."
        last_result="$result"
    else
        echo; echo "end of searching"
        break
    fi
done
echo
echo "$last_result"

date