
결론을 말하자면 그룹핑을 하는 이유는 데이터를 효율적으로 처리하기 위함이다.
어떻게 효율적으로 처리하냐 ? → 데이터가 커질수록 데이터 정제작업이 많은데 그룹핑을하면 데이터를 효율적으로 관리할 수 있다.
CREATE TABLE member (
uid int not null AUTO_INCREMENT PRIMARY KEY, name varchar(50) not null,
age int not null,
gender varchar(6) not null
);
INSERT INTO member (name, age, gender) values ("mike", 25, "male");
{
"name": "mike",
"age": 25,
"gender": "male"
}
name” , “age”, “gender” 를 필드라고 하며, “mike”, 25, “male” 를 값이라고 한다.
엘라스틱서치 매핑으로 필드들의 데이터 타입을 지정할 수 있는데, name, gender 필드는 텍스트 타입, age 필드는 정수 타입으로 매핑이 되어있다.
name” , “age”, “gender” 를 필드라고 하며, “mike”, 25, “male” 를 값이라고 한다.
엘라스틱서치 매핑으로 필드들의 데이터 타입을 지정할 수 있는데, name, gender 필드는 텍스트 타입, age 필드는 정수 타입으로 매핑이 되어있다.
PUT index0/_doc/1
{
"name": "gildong",
"age": 22,
"address": "seoul"
}
#! Elasticsearch built-in security features are not enabled. Without authentication, your cluster could be accessible to anyone. See https://www.elastic.co/guide/en/elasticsearch/reference/7.17/security-minimal-setup.html to enable security.
{
"_index" : "index0",
"_type" : "_doc",
"_id" : "1",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1
}
GET kibana_sample_data_ecommerce/_search
{
"size": 0,
"aggs": {
"range_aggs": {
"range" : {
"field": "products.base_price",
"ranges": [
{ "from": 0, "to": 30 },
{ "from": 30, "to": 50 },
{ "from": 50, "to": 100 },
{ "from": 100, "to": 200 },
{ "from": 200, "to": 1000 }
]
}
}
}
}
{
"took" : 2,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 4675,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
},
"aggregations" : {
"range_aggs" : {
"buckets" : [
{
"key" : "0.0-30.0",
"from" : 0.0,
"to" : 30.0,
"doc_count" : 3882
},
{
"key" : "30.0-50.0",
"from" : 30.0,
"to" : 50.0,
"doc_count" : 1468
},
{
"key" : "50.0-100.0",
"from" : 50.0,
"to" : 100.0,
"doc_count" : 1902
},
{
"key" : "100.0-200.0",
"from" : 100.0,
"to" : 200.0,
"doc_count" : 263
},
{
"key" : "200.0-1000.0",
"from" : 200.0,
"to" : 1000.0,
"doc_count" : 13
}
]
}
}
}
POST index0/_update/1
{
"doc": {
"name": "minsoo"
}
}
{
"_index" : "index0",
"_type" : "_doc",
"_id" : "1",
"_version" : 2,
"_seq_no" : 5,
"_primary_term" : 1,
"found" : true,
"_source" : {
"name" : "minsoo",
"age" : 22,
"address" : "seoul"
}
}
DELETE index0/_doc/3
"max_score" : 1.0,
"hits" : [
{
"_index" : "index0",
"_type" : "_doc",
"_id" : "2",
"_score" : 1.0,
"_source" : {
"name" : "chulsoo",
"age" : 23,
"address" : "busan"
}
},
{
"_index" : "index0",
"_type" : "_doc",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"name" : "minsoo",
"age" : 22,
"address" : "seoul"
}
}
]
}
}
PUT index1
POST _bulk
{"index": {"_index": "index1", "_id": "1"}}
{"name": "gil dong hong", "age": 30, "gender": "male"}
{"index": {"_index": "index1", "_id": "2"}}
{"name": "young hee park", "age": 25, "gender": "female"}
GET index1/_search
{
"took" : 2,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 2,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "index1",
"_type" : "_doc",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"name" : "gil dong hong",
"age" : 30,
"gender" : "male"
}
},
{
"_index" : "index1",
"_type" : "_doc",
"_id" : "2",
"_score" : 1.0,
"_source" : {
"name" : "young hee park",
"age" : 25,
"gender" : "female"
}
}
]
}
}
예를 들어 JSON 도큐먼트에 “age” 20 이라는 필드와 값이 있따면 엘라스틱 서치는 20을 숫자로 인식한다.
원본 소스가 integer 이므로 인덱스 생성시 age 필드를 long 타입의 필드로 매핑한다.
# index1 삭제하기
DELETE index1
# index1 생성 (매핑 수동으로 지정)
PUT index1
{
"mappings": {
"properties": {
"name": {"type": "text"},
"age": {"type": "short"},
"gender": {"type": "keyword"}
}
}
}
# bulk 데이터 전송
POST _bulk
{"index": {"_index": "index1", "_id": "1"}}
{"name": "gil dong hong", "age": 30, "gender": "male"}
{"index": {"_index": "index1", "_id": "2"}}
{"name": "young hee park", "age": 25, "gender": "female"}
# index1에 포함된 도큐먼트 확인
GET index1/_search
# index1에 포함된 필드들의 데이터 타입 확인
GET index1/_mapping
분석기는 반드시 하나의 토크나이저를 포함해야 한다. 토크나이저는 문자열을 분리해 토큰화해준다.분석기에는 반드시 포함해야 하므로 형태에 맞게끔 설정해야 한다.
standard : 스탠다드 분석기가 사용하는 토크나이저, 기본값, 쉼표나 마침표 같은 기호를 제거한다.
lowercase : 텍스트 기반으로 토큰화하며 모든 문자를 소문자로 변경하여 토큰화 해준다.
ngram : N 개의 연속된 글자단위를 모두 토큰화한다.
캐릭터 필터의 예) html 코드의 내용을 불러왔다고 가정해 보자. html 에서 사용하는 태그는 이를 나누고 인덱싱할 필요가 없는 데이터이다. 이러한 쓸모없는 데이터는 캐릭터 필터에서 사전에 삭제해준다.
토크나이저 : 분석기는 반드시 하나의 토크나이저를 포함한다
토큰 필터 : 대문자 -> 소문자, loving/loved/love/loves => love

POST _analyze
{
"analyzer": "standard",
"text": "Hello, my name is gildong hong. She loves him. I am 22 years old"
}
{
"tokens" : [
{
"token" : "hello",
"start_offset" : 0,
"end_offset" : 5,
"type" : "<ALPHANUM>",
"position" : 0
},
{
"token" : "my",
"start_offset" : 7,
"end_offset" : 9,
"type" : "<ALPHANUM>",
"position" : 1
},
{
"token" : "name",
"start_offset" : 10,
"end_offset" : 14,
"type" : "<ALPHANUM>",
"position" : 2
},
{
"token" : "is",
"start_offset" : 15,
"end_offset" : 17,
"type" : "<ALPHANUM>",
"position" : 3
},
{
"token" : "gildong",
"start_offset" : 18,
"end_offset" : 25,
"type" : "<ALPHANUM>",
"position" : 4
},
{
"token" : "hong",
"start_offset" : 26,
"end_offset" : 30,
"type" : "<ALPHANUM>",
"position" : 5
},
{
"token" : "she",
"start_offset" : 32,
"end_offset" : 35,
"type" : "<ALPHANUM>",
"position" : 6
},
{
"token" : "loves",
"start_offset" : 36,
"end_offset" : 41,
"type" : "<ALPHANUM>",
"position" : 7
},
{
"token" : "him",
"start_offset" : 42,
"end_offset" : 45,
"type" : "<ALPHANUM>",
"position" : 8
},
{
"token" : "i",
"start_offset" : 47,
"end_offset" : 48,
"type" : "<ALPHANUM>",
"position" : 9
},
{
"token" : "am",
"start_offset" : 49,
"end_offset" : 51,
"type" : "<ALPHANUM>",
"position" : 10
},
{
"token" : "22",
"start_offset" : 52,
"end_offset" : 54,
"type" : "<NUM>",
"position" : 11
},
{
"token" : "years",
"start_offset" : 55,
"end_offset" : 60,
"type" : "<ALPHANUM>",
"position" : 12
},
{
"token" : "old",
"start_offset" : 61,
"end_offset" : 64,
"type" : "<ALPHANUM>",
"position" : 13
}
]
}
# 전문 쿼리 실습
PUT text_index
{
"mappings": {
"properties": {
"writer": {"type" : "keyword"},
"title": {"type": "text"}
}
}
}
PUT text_index/_doc/1
{
"wirter": "gildong",
"title": "The Cloud Computing Rules"
}
PUT text_index/_doc/2
{
"writer": "chulsoo",
"title": "My Cloud Bread"
}
# 전체 검색
GET text_index/_search
{
"query": {
"match": {
"title": "Cloud Computing"
}
}
}
# 작가 검색
GET text_index/_search
{
"query": {
"match": {
"writer": "gildong"
}
}
}
# 제목 검색
GET text_index/_search
{
"query": {
"match": {
"title": "Cloud"
}
}
}
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 2,
"relation" : "eq"
},
"max_score" : 0.82713,
"hits" : [
{
"_index" : "text_index",
"_type" : "_doc",
"_id" : "1",
"_score" : 0.82713,
"_source" : {
"wirter" : "gildong",
"title" : "The Cloud Computing Rules"
}
},
{
"_index" : "text_index",
"_type" : "_doc",
"_id" : "2",
"_score" : 0.19363807,
"_source" : {
"writer" : "chulsoo",
"title" : "My Cloud Bread"
}
}
]
}
}
# 인덱스 템플릿 만들기
PUT _index_template/mysql_2024_template
{
"index_patterns": ["mysql_2024_*"],
"priority": 1,
"template": {
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1
},
"mappings": {
"properties": {
"name": {"type": "keyword"},
"time" : {"type": "date"},
"message": {"type": "text"}
}
}
}
}
GET mysql_2024_02/_mapping
[결과]
{
"mysql_2024_02" : {
"mappings" : {
"properties" : {
"message" : {
"type" : "text"
},
"name" : {
"type" : "keyword"
},
"time" : {
"type" : "date"
}
}
}
}
}
인덱스이름이 패턴 mysql_2024_* 에 매치하여 자동으로 타입이 결정된다.
POST _analyze
{
"tokenizer": "standard",
"text": "email: test@test.com"
}
POST _analyze
{
"tokenizer": "lowercase",
"text": "email: test@test.com"
}
POST _analyze
{
"tokenizer": "uax_url_email",
"text": "email: test@test.com"
}
{
"tokens" : [
{
"token" : "email",
"start_offset" : 0,
"end_offset" : 5,
"type" : "<ALPHANUM>",
"position" : 0
},
{
"token" : "test",
"start_offset" : 7,
"end_offset" : 11,
"type" : "<ALPHANUM>",
"position" : 1
},
{
"token" : "test.com",
"start_offset" : 12,
"end_offset" : 20,
"type" : "<ALPHANUM>",
"position" : 2
}
]
}
{
"tokens" : [
{
"token" : "email",
"start_offset" : 0,
"end_offset" : 5,
"type" : "<ALPHANUM>",
"position" : 0
},
{
"token" : "test@test.com",
"start_offset" : 7,
"end_offset" : 20,
"type" : "<EMAIL>",
"position" : 1
}
]
}