반응형
ELK(elasticsearch + logstash + kibina) 스터디 내용입니다. ELK를 처음 접하느라 Elastic 홈페이지에 소개하는 튜토리얼 동영상을 보며 따라했습니다. 튜토리얼 동영상에 나오는 github 주소는 여기입니다. 아래 정리한 데는 강사의 설명을 모두 주석으로 처리했습니다.
➜ bin curl localhost:9200
{
"name" : "호스트 이름.local",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "G_3I66A5Ru-gqjWS7GCsVQ",
"version" : {
"number" : "7.7.0",
"build_flavor" : "default",
"build_type" : "tar",
"build_hash" : "81a1e9eda8e6183f5237786246f6dced26a10eaf",
"build_date" : "2020-05-12T02:01:37.602180Z",
"build_snapshot" : false,
"lucene_version" : "8.5.1",
"minimum_wire_compatibility_version" : "6.8.0",
"minimum_index_compatibility_version" : "6.0.0-beta1"
},
"tagline" : "You Know, for Search"
}
➜ bin curl -XPUT "http://localhost:9200/my_index/_doc/1" -H 'Content-Type: application/json' -d' {"message":"안녕하세요 Elasticsearch"}' # XPUT: 텍스트 입력 command
{"_index":"my_index","_type":"_doc","_id":"1","_version":1,"result":"created","_shards":{"total":2,"successful":1,"failed":0},"_seq_no":0,"_primary_term":1}%
➜ bin curl -XGET http://localhost:9200/my_index/_doc/1{"_index":"my_index","_type":"_doc","_id":"1","_version":1,"_seq_no":0,"_primary_term":1,"found":true,"_source": {"message":"안녕하세요 Elasticsearch"}}%
# XGET: 입력이 잘되었는지 확인
➜ bin curl -XPUT "http://localhost:9200/my_index/_doc/1" -H 'Content-Type: application/json' -d' {"message":"안녕하세요 Elastic Stack"}'
{"_index":"my_index","_type":"_doc","_id":"1","_version":2,"result":"updated","_shards":{"total":2,"successful":1,"failed":0},"_seq_no":1,"_primary_term":1}%
➜ bin curl -XGET http://localhost:9200/my_index/_doc/1{"_index":"my_index","_type":"_doc","_id":"1","_version":2,"_seq_no":1,"_primary_term":1,"found":true,"_source": {"message":"안녕하세요 Elastic Stack"}}%
➜ bin curl -XPOST "http://localhost:9200/my_index/_doc" -H 'Content-Type: application/json' -d' {"message":"안녕하세요 Kibana"}'
# XPOST: _doc으로만 디렉토리 설정(전과 같이 1을 작성하지 않음 => 결과로 랜덤하게 id가 주어짐)
{"_index":"my_index","_type":"_doc","_id":"qvaiO3IBJ5rsE_UkQUFH","_version":1,"result":"created","_shards":{"total":2,"successful":1,"failed":0},"_seq_no":2,"_primary_term":1}%
➜ bin curl localhost:9200/my_index/_doc/qvaiO3IBJ5rsE_UkQUFH{"_index":"my_index","_type":"_doc","_id":"qvaiO3IBJ5rsE_UkQUFH","_version":1,"_seq_no":2,"_primary_term":1,"found":true,"_source": {"message":"안녕하세요 Kibana"}}%
➜ bin curl -XDELETE "http://localhost:9200/my_index/_doc/1"{"_index":"my_index","_type":"_doc","_id":"1","_version":3,"result":"deleted","_shards":{"total":2,"successful":1,"failed":0},"_seq_no":3,"_primary_term":1}%
# XDELETE: 도큐먼트 삭제
➜ bin curl -XGET http://localhost:9200/my_index/_doc/1
{"_index":"my_index","_type":"_doc","_id":"1","found":false}%
➜ bin curl -XDELETE http://localhost:9200/my_index # 인덱스 단위로도 삭제 가능
{"acknowledged":true}%
➜ bin curl -XGET http://localhost:9200/my_index/_doc/1
{"error":{"root_cause":[{"type":"index_not_found_exception","reason":"no such index [my_index]","resource.type":"index_expression","resource.id":"my_index","index_uuid":"_na_","index":"my_index"}],"type":"index_not_found_exception","reason":"no such index [my_index]","resource.type":"index_expression","resource.id":"my_index","index_uuid":"_na_","index":"my_index"},"status":404}%
---------------------------------------------------------------------------
# Kibana localhost 사이트에 들어가서 작업 시작
# Kibana 사이트와 Elasticsearch 사이트는 디폴트로 다르게 설정되어 있으나 이후 같은 공간에서 작업 가능
PUT my_index/_doc/1
{
"message":"안녕하세요 여러분"
}
# Bulk 색인
# 다량의 도큐먼트를 한꺼번에 색인 할 때는 반드시 bulk API 사용(속도 약 10배 차이)
POST my_index/_bulk
{"index":{"_id":1}}
{"message":"The quick brown fox"}
{"index":{"_id":2}}
{"message":"The quick brown fox jumps over the lazy dong"}
{"index":{"_id":3}}
{"message":"The quick brown fox jumps over the quick dong"}
{"index":{"_id":4}}
{"message":"Brown fox brown dong"}
{"index":{"_id":5}}
{"message":"Lazy jumping dog"}
# 풀텍스트 검색(_search)
# 인덱스의 전체 도큐먼트 검색: match_all
# 기본 디폴트 검색 사이즈는 10개 => "size":3 와 같이 추가 명령어로 조절 가능
GET my_index/_search
{
"query":{
"match_all":{ }
}
}
#match 쿼리: dog 검색
GET my_index/_search
{
"query": {
"match": {
"message":"dog"
}
}
}
# match 쿼리: quick 또는 dog 검색(or)
# 띄어쓰기 = or의 의미
GET my_index/_search
{
"query": {
"match": {
"message": "quick dog"
}
}
}
# match 쿼리: quick과 dog 검색(and)
GET my_index/_search
{
"query": {
"match": {
"message": {
"query": "quick dog",
"operator": "and"
}
}
}
}
# match_phrase 쿼리: "lazy dog" 구문 검색
GET my_index/_search
{
"query": {
"match_phrase": {
"message": "lazy dog"
}
}
}
# 복합 쿼리 - bool 쿼리를 이용한 서브쿼리 조합
# must: 쿼리가 참인 도큐먼트들을 검색
# must_not: 쿼리가 거짓인 도큐먼트들을 검색
# should: 검색 결과중 이 쿼리에 해당하는 도큐먼트의 점수를 높임
# must에 해당하는 도큐먼트들 중 should 조건을 만족하면 랭킹 점수라고 하는 스코어가 올라감(스코어가 높을수록 먼저 가져오게 됨)
# filter: 쿼리가 참인 도큐먼트를 검색하여 조건을 만족하지 않는 도뮤컨트들은 제거하는 것으로 스코어를 계산하지 않음, must보다 검색 속도가 빠르고 캐싱됨
# "quick"과 "lazy dog"가 포함된 모든 문서 검색
GET my_index/_search
{
"query": {
"bool": {
"must": [
{
"match": {"message":"quick"}
},
{
"match_phrase": {"message":"lazy dog"}
}
]
}
}
}
# "fox"를 포함하는 모든 도큐먼트 중 "lazy"가 포함된 결과에 가중치 부여
GET my_index/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"message":"fox"
}
}
],
"should": [
{
"match": {
"message":"lazy"
}
}
]
}
}
}
# "fox"와 "quick"을 포함하는 쿼리의 must & filter 스코어 비교
GET my_index/_search
{
"query": {
"match": {
"message": "fox"
}
}
}
GET my_index/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"message": "fox"
}
},
{
"match": {
"message": "quick"
}
}
]
}
}
}
GET my_index/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"message":"fox"
}
}
],
"filter": [
{
"match": {
"message":"quick"
}
}
]
}
}
}
---------------------------------------------------------------------------
# range 쿼리(숫자나 날짜 쿼리)
# gte(Greater-than or equal to): 이상(같거나 큼)
# gt(Greater-than): 초과(큼)
# lte(Less-than or euqual to): 이하(같거나 작음)
# lt(Less-than): 미만(작음)
POST phones/_bulk
{"index":{"_id":1}}
{"model":"Samsung GalaxyS 5","price":475,"date":"2014-02-24"}
{"index":{"_id":2}}
{"model":"Samsung GalaxyS 6","price":795,"date":"2015-03-15"}
{"index":{"_id":3}}
{"model":"Samsung GalaxyS 7","price":859,"date":"2016-02-21"}
{"index":{"_id":4}}
{"model":"Samsung GalaxyS 8","price":959,"date":"2017-03-29"}
{"index":{"_id":5}}
{"model":"Samsung GalaxyS 9","price":1059,"date":"2018-02-25"}
# price 필드 값이 700 이상, 900 미만인 데이터를 검색
GET phones/_search
{
"query": {
"range": {
"price": {
"gte": 700,
"lt": 900
}
}
}
}
# data 필드 날짜가 2016년 1월 1일 이후인 도큐먼트들을 검색
GET phones/_search
{
"query": {
"range": {
"date": {
"gt": "2016-01-01"
}
}
}
}
# data 필드 날짜가 오늘(2020년 5월 23일)부터 4년 전 이후인 도큐먼트들을 검색
GET phones/_search
{
"query": {
"range": {
"date": {
"gt": "now-36M" # y(연도) M(월) d(일) H(시간) m(분) s(초) 단위 모두 가능
}
}
}
}
---------------------------------------------------------------------------
# 텍스트 분석 - Analysis(_analyze API)
# Tokenizer을 통해 문장을 검색어 텀(term)으로 쪼갬
GET my_index/_analyze
{
"tokenizer": "standard",
"text": "Brown fox brown dog"
}
# Filter(토큰필터)를 통해 쪼개진 텀들을 가공
# lowercase - 소문자로 변경
GET my_index/_analyze
{
"tokenizer": "standard",
"filter": [
"lowercase"
],
"text": "Brown fox brown dog"
}
# unique - 중복 텀 제거
GET my_index/_analyze
{
"tokenizer": "standard",
"filter": [
"lowercase",
"unique"
],
"text": "Brown brown brown fox brown dog"
}
# (standard Tokenizer + lowercase Filter) 대신 Analyzer 사용
GET my_index/_analyze
{
"analyzer": "standard",
"text": "Brown fox brown dog"
}
# 분석 과정 이해하기
# 복합적인 문장 분석 - T:standard, F:lowercase
GET my_index/_analyze
{
"tokenizer": "standard",
"filter": [
"lowercase"
],
"text": "THE quick.brown_FOx jumped! $19.95 @ 3.0"
}
# 복합적인 문장 분석 - T:letter, F:lowercase
# 문자를 제외한 기호 모두 제거
GET my_index/_analyze
{
"tokenizer": "letter",
"filter": [
"lowercase"
],
"text": "THE quick.brown_FOx jumped! $19.95 @ 3.0"
}
# Email, URL 분석 - T:standard
GET my_index/_analyze
{
"tokenizer": "standard",
"text": "elastic@example.com website: https://www.elastic.co"
}
# Email, URL 분석 - T:uax_url_email
# 이메일 형태, 주소 형태 유지한 채로 변환
# ex) elastic@example.com / https://www.elastic.co
GET my_index/_analyze
{
"tokenizer": "uax_url_email",
"text": "elastic@example.com website: https://www.elastic.co"
}
--------------------------------------------------------------------------------
# 한글 형태소 분석기 nori 설치
# $ bin/elasticsearch-plugin install analysis-nori
# nori_tokenizer를 이용한 한글 분석(standard tokenizer와 비교)
# ex) 동해/물/과/백두/산/이
GET _analyze
{
"tokenizer": "standard"
"text": ["동해물과 백두산이"]
}
GET _analyze
{
"tokenizer": "nori_tokenizer",
"text": ["동해물과 백두산이"]
}
--------------------------------------------------------------------------------
# 인덱스 생성
# settings: analyzer, 샤드 수, 리프레시 주기 등을 설정
# maapings: 각 필드별 데이터 명세를 정의(텍스트, 숫자 필드? 각 필드는 어떤 애널라이져를 사용할지?)
# 사용자 정의 analyzer
# settings, mappings는 한 번 설정하면 대부분 수정하기 어렵기 때문에 생성할 때 주의하자!
PUT my_index_2
{
"settings": {
"analysis": {
"analyzer": {
"my_analyzer": {
"tokenizer": "letter",
"filter": [
"lowercase",
"stop" # stopwords(is, the)
]
}
}
}
},
"mappings": {
"properties": {
"message": {
"type": "text",
"analyzer": "my_analyzer"
}
}
}
}
# 사용자 정의 analyzer 필드에 데이터 색인
PUT my_index_2/_doc/1
{
"message": "THE quick.brown_FOx jumped! $19.95 @ 3.0"
}
# 데이터 검색
# letter tokenizer를 설정했기 때문에 quick.brown_FOx 부분은 잘 분리됨
GET my_index_2/_search
{
"query": {
"match": {
"message": "brown"
}
}
}
# stopwords를 설정했기 때문에 the는 검색되지 않음
GET my_index_2/_search
{
"query": {
"match": {
"message": "the"
}
}
}
--------------------------------------------------------------------------------
# 애그리게이션 - 집계(Aggregation)
# metrics: min, max, sum, avg 등의 계산
# bucket: 특정 기준으로 도큐먼트들을 그룹화
PUT my_stations/_bulk
{"index": {"_id":"1"}}
{"date": "2019-06-01", "line": "1호선", "station": "종각", "passangers": 2314}
{"index": {"_id":"2"}}
{"date": "2019-06-01", "line": "2호선", "station": "강남", "passangers": 5412}
{"index": {"_id":"3"}}
{"date": "2019-07-10", "line": "2호선", "station": "강남", "passangers": 6221}
{"index": {"_id":"4"}}
{"date": "2019-07-15", "line": "2호선", "station": "강남", "passangers": 6478}
{"index": {"_id":"5"}}
{"date": "2019-08-07", "line": "2호선", "station": "강남", "passangers": 5821}
{"index": {"_id":"6"}}
{"date": "2019-08-18", "line": "2호선", "station": "강남", "passangers": 5724}
{"index": {"_id":"7"}}
{"date": "2019-09-02", "line": "2호선", "station": "신촌", "passangers": 3912}
{"index": {"_id":"8"}}
{"date": "2019-09-11", "line": "3호선", "station": "양제", "passangers": 4121}
{"index": {"_id":"9"}}
{"date": "2019-09-20", "line": "3호선", "station": "홍제", "passangers": 1021}
{"index": {"_id":"10"}}
{"date": "2019-10-01", "line": "3호선", "station": "불광", "passangers": 971}
# 전체 passangers 필드값의 합계를 가져오는 metrics aggregation
GET my_stations/_search
{
"size": 0, # size=0을 하면 우리가 원하는 모든 승객수만 반환 <-> size=0이 없다면 각 지하철역의 정보까지 동시에 반환
"aggs": {
"all_passangers": {
"sum": {
"field": "passangers"
}
}
}
}
# "station": "강남"인 도큐먼트의 passangers 필드값의 합계를 가져오는 metrics aggregation
GET my_stations/_search
{
"query": {
"match": {
"station": "강남"
}
},
"size": 0,
"aggs": {
"gangnam_passangers": {
"sum": {
"field": "passangers"
}
}
}
}
# date_histogram으로 date 필드를 1개월 간격으로 구분하는 bucket aggregation
# 해당하는 도큐먼트 개수 반환
GET my_stations/_search
{
"size":0,
"aggs": {
"date_his": {
"date_histogram": {
"field": "date",
"interval": "month"
}
}
}
}
# stations.keyword 필드 별로 passangers 필드의 평균값을 계산하는 bucket & metrics aggregation
GET my_stations/_search
{
"size":0,
"aggs": {
"stations": {
"terms": {
"field": "station.keyword"
},
"aggs": {
"avg_psg_per_st": {
"avg": {
"field": "passangers"
}
}
}
}
}
}
--------------------------------------------------------------------------------
# Geo - 위치 정보
# geo_point : {"lat": 41.12, "lon": -71.34} 같은 형식으로 입력
# geo_point 타입의 location 필드 선언
PUT my_geo
{
"mappings": {
"properties": {
"location": {
"type": "geo_point"
}
}
}
}
# 예제 데이터 입력
# location 단위로 위도, 경도 입력
# 그냥 위도, 경도를 입력하면 실수 필드 더블 타입으로 들어가기 때문에 geo_point 타입을 통해 location이라는 단위 필드에 속하도록
PUT my_geo/_bulk
{"index":{"_id":"1"}}
{"station":"강남", "location": {"lon":127.027926, "lat":37.497175}, "line": "2호선"}
{"index":{"_id":"2"}}
{"station":"종로3가", "location": {"lon":126.991806, "lat":37.571607}, "line": "3호선"}
{"index":{"_id":"3"}}
{"station":"여의도", "location": {"lon":126.924191, "lat":37.521624}, "line": "5호선"}
{"index":{"_id":"4"}}
{"station":"서울역", "location": {"lon":126.972559, "lat":37.554648}, "line": "1호선"}
# geo_bounding_box: 두 점을 기준으로 하는 네모 안에 있는 도큐먼트들을 가져옴
GET my_geo/_search
{
"query": {
"geo_bounding_box": {
"location": {
"bottom_right": {
"lat": 37.4899,
"lon": 127.0388
},
"top_left": {
"lat": 37.5779,
"lon": 126.9617
}
}
}
}
}
# geo_distance: 한 점을 기준으로 반경 안에 있는 도큐먼트들을 가져옴
GET my_geo/_search
{
"query": {
"geo_distance": {
"distance": "5km",
"location": {
"lat": 37.5358,
"lon": 126.9559
}
}
}
}
참고 : should는 스코어 계산 후 랭킹을 매겨 가장 높은 점수의 도큐먼트를 상위에 출력
{
"took" : 9,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 4,
"relation" : "eq"
},
"max_score" : 0.94896436,
"hits" : [
{
"_index" : "my_index",
"_type" : "_doc",
"_id" : "2",
"_score" : 0.94896436,
"_source" : {
"message" : "The quick brown fox jumps over the lazy dog"
}
}
여기까지가 가장 기본적인 Elasticsearch 활용 방법입니다. 여기서 Kibina에 접속하긴 했지만 저희가 일반적으로 생각하는 시각화 도구는 하나도 사용하지 않았습니다. Kibina UI에서 Dev tools만 사용했습니다.
728x90
반응형
'문돌이 존버 > ELK 스터디' 카테고리의 다른 글
Django MySQL 멀티 테이블 데이터 처리를 위한 Logstash conf 파일 설정 (0) | 2020.08.15 |
---|---|
AWS EC2 Ubuntu 18.04에 ELK 설치 + Linux 2 AMI에 Django 설치 (2) | 2020.08.14 |
Mac 버전 장고(Django), MySQL, Logstash 연동 튜토리얼 (0) | 2020.08.12 |
Kibana map 시각화에 필요한 geo_point 생성 (2) | 2020.06.13 |
ELK 보안 설정과 logstash conf 파일 기초 (0) | 2020.06.04 |