
๋ฌธ์ ์ํฉ
์ด๋ ๋ ๊ฐ์๊ธฐ ํ์์ด ์ฐพ์์์ ๋งํ๋ค.
"์ง๊ธ ๋ก๊ทธ์์ ์ฌ์ฉ์ ์ ํธ ๊ตญ๊ฐ ๋ฐ์ดํฐ๋ฅผ ์๊ฐํํ๋๋ฐ, 5๊ฐ๋ฅผ ๊ณ ๋ฅธ ์ ์ ์ 1๊ฐ๋ง ๊ณ ๋ฅธ ์ ์ ์ ๋ฐ์ดํฐ๊ฐ ๊ฐ์ด ์์ด๊ณ ์์ด์ ์๊ณก์ด ์๊ธฐ๋ ๊ฒ ๊ฐ์์. ๊ตญ๊ฐ๋ณ๋ก ๊ด๊ณ ์บ ํ์ธ์ ์งํํด์ผํ๋๋ฐ, ๋นจ๋ฆฌ ํ์ธํด๋ณผ ์ ์์๊น์?"
๋ง๋ ๋ง์ด์๋ค. 'ํ๊ตญ'๋ง์ ์ ํธํ๋ ์ฌ์ฉ์์ 5๊ฐ ๊ตญ๊ฐ ์ค ํ๋๋ก ํ๊ตญ์ ํฌํจ์ํจ ์ฌ์ฉ์์ ๋ฐ์ดํฐ๊ฐ ๋์ผํ ๊ฐ์ค์น๋ก ์ง๊ณ๋๋ค๋ฉด, ์ค์ ์ ํธ๋๋ฅผ ์ ๋๋ก ๋ฐ์ํ๊ธฐ ์ด๋ ค์ธ ๊ฒ์ด๋ค.
"๊ทธ๋ผ, ์ ํํ ๊ฐ์์ ๋ฐ๋ผ ๊ฐ์ค์น๋ฅผ ๊ณ์ฐํด์ ํ๋๋ก ์ ๊ณตํด๋๋ฆด๊น์? ์๋ฅผ ๋ค์ด 1๊ฐ ์ ํํ๋ฉด 1.0, 5๊ฐ ์ ํํ๋ฉด ๊ฐ๊ฐ 0.2์ฉ ๋ถ์ฌํ๋ ์์ด๋ฉด ์ ํํ์ง ์์๋, ์ง๊ธ๋ณด๋ค๋ ํจ์ฌ ์ ํํ ๊ฑฐ์์."
ํ์๋ ์ข์ ์์ด๋์ด๋ผ๊ณ ๋์ํ๋ฉฐ ๋ฐ๋ก ํ์ฌ ์ํฉ์ ๋ถ์ํ๊ธฐ ์์ํ๋ค. ๊ธฐ์กด Elasticsearch์๋ ์ด๋ฏธ ์์ญ์ต ๊ฑด์ ๋ก๊ทธ๊ฐ ์์ฌ์์๊ณ , user.preferences.preferRegion ํ๋๋ ์กด์ฌํ์ง๋ง ๊ฐ์ค์น ํ๋๋ ์๋ ์ํฉ์ด์๋ค. ๋์ฑ์ด ์ด ๋ฌธ์ ๋ ์์ฒญ๋ ๋ฐ์ดํฐ๊ฐ ์ค์๊ฐ์ผ๋ก ๊ณ์ ์ ์ ๋๊ณ ์๋ค๋ ์ ์ด์๋ค.
์ฒซ ๋ฒ์งธ ์ ๊ทผ: Update By Query์ ํจ์
์ฒ์ ์๊ฐ์ ๊ฐ๋จํ๋ค. "๊ทธ๋ฅ update_by_query๋ก ๊ธฐ์กด ๋ฐ์ดํฐ๋ฅผ ์ ๋ฐ์ดํธํ๋ฉด ๋๊ฒ ๋ค!"
POST /*-log-[service]-*/_update_by_query
{
"script": {
"source": """
def preferRegion = ctx._source.user?.preferences?.preferRegion;
def size = 0;
if (preferRegion instanceof String) {
size = (preferRegion == "ALL") ? 0 : 1;
} else if (preferRegion instanceof List) {
size = preferRegion.size();
}
if (size >= 5) ctx._source.preferRegion_weight = 0.2;
else if (size == 4) ctx._source.preferRegion_weight = 0.25;
// ... ์ดํ ์๋ต
"""
}
}
ํ ์คํธ ์ธ๋ฑ์ค๋ก ๋๋ ค๋ณด๋๊น... 1N์ต ๊ฑด ์ฒ๋ฆฌํด์ผํ๋๋ฐ ๋๋ต 80์๊ฐ์ด ๊ฑธ๋ฆด ๊ฒ ๊ฐ๋ค๊ณ ๋์๋ค. ์ด๊ฑฐ ์ด์์์ ๋๋ฆฌ๋ฉด ์๋น์ค ํฐ์ง๋ค. ๊ทผ๋ฐ ๋ก๊ทธ ํน์ฑ์ ์ต์ ๋ก๊ทธ๋ฅผ ๋ฐ์ํ๋ฉด ๋๋ค๋ ๊ฒ์ ์๊ณ , ์ต๊ทผ 24์๊ฐ ๋ฐ์ดํฐ๋ถํฐ ์ฒ๋ฆฌํด๋ณผ๊น?" ์ถ์ด์ ๋ฒ์๋ฅผ ์ขํ์ ์๋ํด๋ดค๋ค.
```json
POST /*-log-[service]-*/_update_by_query
{
"query": {
"range": {
"@timestamp": {
"gte": "now-24h"
}
}
},
"script": {
"source": "..."
}
}
์ต๊ทผ ํ๋ฃจ ๋ฐ์ดํฐ๋ ๋๋ต 1000๋ง ๊ฑด ์ ๋์๋๋ฐ, ์ด๊ฒ๋ 30๋ถ์ ๊ฑธ๋ ธ๋ค. ๊ทธ๋ฆฌ๊ณ ๋ฌด์๋ณด๋ค ์น๋ช ์ ์ธ ๋ฌธ์ ๊ฐ ์์๋ค - ์๋ก ๋ค์ด์ค๋ ๋ฐ์ดํฐ์๋ ์ฌ์ ํ ๊ฐ์ค์น๊ฐ ์ถ๊ฐ๋์ง ์๋๋ค๋ ๊ฒ! ๋งค์ผ ์ด๋ฐ ์์ผ๋ก ๋ฐฐ์น๋ฅผ ๋๋ ค์ผ ํ๋ค๋ฉด ์ด์ ๋ถ๋ด์ด ๋๋ฌด ํด ๊ฒ ๊ฐ์๋ค.
๋ ๋ฒ์งธ ์๋: Ingest Pipeline ๋ฐ๊ฒฌ
๋ค๋ฅธ ๋ฐฉ๋ฒ์ ์ฐพ์๋ณด๋ค๊ฐ Ingest Pipeline์ด๋ผ๋ ๊ฑธ ์๊ฒ ๋์๋ค. ์๋ก ๋ค์ด์ค๋ ๋ฐ์ดํฐ์ ์๋์ผ๋ก ์ ์ฒ๋ฆฌ๋ฅผ ์ ์ฉํ๋ ๋ฐฉ์์ด์๋ค.
PUT _ingest/pipeline/add_region_weight
{
"description": "Add preferRegion_weight based on preferRegion size",
"processors": [
{
"script": {
"source": """
if (ctx.user?.preferences?.preferRegion != null) {
def preferRegion = ctx.user.preferences.preferRegion;
def size = 0;
if (preferRegion instanceof String) {
size = (preferRegion == "ALL") ? 0 : 1;
} else if (preferRegion instanceof List) {
size = preferRegion.size();
}
if (size >= 5) ctx.preferRegion_weight = 0.2;
else if (size == 4) ctx.preferRegion_weight = 0.25;
else if (size == 3) ctx.preferRegion_weight = 0.33;
else if (size == 2) ctx.preferRegion_weight = 0.5;
else ctx.preferRegion_weight = 1.0;
} else {
ctx.preferRegion_weight = 1.0;
}
"""
}
}
]
}
ํ ์คํธํด๋ณด๋ ์ ์๋ํ๋ค. ํ์ง๋ง ์ฌ๊ธฐ์ ์ฒซ ๋ฒ์งธ ์ฝ์ง์ด ์์๋์๋ค.
์ธ ๋ฒ์งธ ๋๊ด: Index Template ์ฐ์ ์์ ์ง์ฅ
ํ์ดํ๋ผ์ธ๋ง ๋ง๋ค์ด์๋ ์๋ก ์์ฑ๋๋ ์ธ๋ฑ์ค์ ์๋์ผ๋ก ์ ์ฉ๋์ง ์์๋ค. Index Template์ด ํ์ํ๋ค.
PUT _index_template/log-service-template
{
"index_patterns": ["*-log-[service]-*"],
"priority": 200,
"template": {
"settings": {
"index.default_pipeline": "add_region_weight"
}
}
}
๊ทธ๋ฐ๋ฐ ์ด๊ฒ ์ฌ๊ฑธ? ์๋ฌ๊ฐ ํฐ์ก๋ค.
index template [log-service-template] has index patterns [*-log-[service]-*]
matching patterns from existing templates with patterns that have the same priority [200]
์๊ณ ๋ณด๋ Elasticsearch์๋ ์๋ง์ ๊ธฐ๋ณธ ํ ํ๋ฆฟ๋ค์ด ์์๊ณ , ๋ค๋ค 200์ ์ฌ์ฉํ๊ณ ์์๋ค. 500์ผ๋ก ์ฌ๋ ค๋ ์ ๋๊ณ , 1000์ผ๋ก ์ฌ๋ ค๋ ์ ๋๊ณ ... ๊ฒฐ๊ตญ 3000์ผ๋ก ์ฌ๋ ค์์ผ ์ฑ๊ณตํ๋ค.
{
"index_patterns": ["*-log-[service]-*"],
"priority": 3000,
"template": {
"settings": {
"index.default_pipeline": "add_region_weight"
}
}
}
๋ค ๋ฒ์งธ ๊นจ๋ฌ์: ๊ธฐ์กด ์ธ๋ฑ์ค๋ ๋ฐ๋ก ์ฒ๋ฆฌํด์ผ ํ๋ค
Template์ ์๋ก ์์ฑ๋๋ ์ธ๋ฑ์ค์๋ง ์ ์ฉ๋๋ค๋ ๊ฑธ ๋ค๋ฆ๊ฒ ์์๋ค. ๊ธฐ์กด ์ธ๋ฑ์ค๋ค์ ์๋์ผ๋ก ํ์ดํ๋ผ์ธ์ ์ ์ฉํด์ผ ํ๋ค.
PUT /*-log-[service]-*/_settings
{
"index.default_pipeline": "add_region_weight"
}
๋คํํ ์ด ์์ ์ ๋ฉํ๋ฐ์ดํฐ๋ง ์์ ํ๋ ๊ฑฐ๋ผ ๋ช ์ด ๋ง์ ๋๋ฌ๋ค.
๊ฐ์ฅ ์ค์ํ ๊ฑด ์ ๋๋ก ์๋ํ๋์ง ํ์ธํ๋ ๊ฒ์ด์๋ค. _simulate API๋ฅผ ์ฌ์ฉํด์ ํ์ดํ๋ผ์ธ์ ํ ์คํธํด๋ดค๋ค.
POST _ingest/pipeline/add_region_weight/_simulate
{
"docs": [
{
"_source": {
"user": {
"preferences": {
"preferRegion": ["KR", "US"]
}
}
}
}
]
}
๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ ์ ํํ 0.5๊ฐ ๋์๋ค. ๋๋์ด ์ ๋๋ก ์๋ํ๋ค!
์ด์ ๋ชจ๋ํฐ๋ง๊ณผ ์ง์์ ์ธ ๊ด๋ฆฌ
ํ์ดํ๋ผ์ธ์ ์ ์ฉํ ํ์๋ ์ง์์ ์ธ ๋ชจ๋ํฐ๋ง์ด ํ์ํ๋ค. ์ค์ ๋ฐ์ดํฐ์ ํ๋๊ฐ ์ ์ถ๊ฐ๋๊ณ ์๋์ง ํ์ธํ๋ ์ฟผ๋ฆฌ๋ฅผ ๋ง๋ค์๋ค.
GET /*-log-[service]-*/_search
{
"query": {
"range": {
"@timestamp": {
"gte": "now-1h"
}
}
},
"_source": ["@timestamp", "preferRegion_weight", "user.preferences.preferRegion"],
"size": 10
}
๊ฐ์ค์น ๋ถํฌ๋ ํ์ธํด์ ์๋ํ ๋๋ก ์ฒ๋ฆฌ๋๊ณ ์๋์ง ์ฒดํฌํ๋ค.
GET /*-log-[service]-*/_search
{
"size": 0,
"aggs": {
"weight_distribution": {
"terms": {
"field": "preferRegion_weight",
"size": 10
}
}
}
}
๋ง์ง๋ง ํจ์ : Kibana์์ ํ๋๊ฐ ์ ๋ณด์ธ๋ค
Kibana Discover์์ ์ ํ๋๊ฐ ๋ณด์ด์ง ์์๋ค. ์๊ณ ๋ณด๋ Data View์์ ํ๋ ๋ชฉ๋ก์ ์๋ก๊ณ ์นจํด์ผ ํ๋ค. Stack Management → Data Views → Refresh field list๋ฅผ ๋๋ฅด๋๊น ๋๋์ด ํ๋๊ฐ ๋ณด์๋ค.
๋ง์น๋ฉฐ
์ด๋ฒ ์์ ์ ํตํด ๋ฐฐ์ด ๊ฒ๋ค์ ์๋์ ๊ฐ๋ค.
Ingest Pipeline ์์ฐ์: Update By Query๋ก ๋ช ์๊ฐ ๊ฑธ๋ฆด ์์ ์ ์ค์๊ฐ์ผ๋ก ์ฒ๋ฆฌํ ์ ์๋ค. ์๋ก ๋ค์ด์ค๋ ๋ฐ์ดํฐ์ ์๋์ผ๋ก ์ ์ฉ๋๋๊น ํ ๋ฒ ์ค์ ํด๋์ผ๋ฉด ๋์ด๋ค.
Index Template ์ฐ์ ์์: Elasticsearch ๊ธฐ๋ณธ ํ ํ๋ฆฟ๋ค์ด ์๊ฐ๋ณด๋ค ๋ง๋ค. ์ฌ์ฉ์ ์ ์ ํ ํ๋ฆฟ์ 1000 ์ด์์ ๋์ ์ฐ์ ์์๋ฅผ ์ฌ์ฉํ๋ ๊ฒ ์์ ํ๋ค.
๋จ๊ณ๋ณ ๊ฒ์ฆ์ ์ค์์ฑ: _simulate API๋ก ํ์ดํ๋ผ์ธ ๋ก์ง์ ๋ฏธ๋ฆฌ ๊ฒ์ฆํ๊ณ , ์ค์ ๋ฐ์ดํฐ๋ก ํ ์คํธํ๊ณ , Kibana UI๊น์ง ํ์ธํ๋ ์ ์ฒด ํ๋ก์ฐ๋ฅผ ๊ฒ์ฆํด์ผ ํ๋ค.
์ง์์ ๋ชจ๋ํฐ๋ง: ํ์ดํ๋ผ์ธ์ ์ ์ฉํ ํ์๋ ์ค์ ๋ฐ์ดํฐ ์ ์ฉ๋ฅ , ์ฑ๋ฅ ์ํฅ, ๊ฐ์ค์น ๋ถํฌ ๋ฑ์ ์ง์์ ์ผ๋ก ๋ชจ๋ํฐ๋งํด์ผ ํ๋ค.
๊ฒฐ๊ตญ ์ฒ์ ์์ํ๋ ๊ฒ๋ณด๋ค ํจ์ฌ ๋ณต์กํ์ง๋ง, ํ ๋ฒ ์ ๋๋ก ๊ตฌ์ถํด๋์ผ๋ ๋งค์ผ ์๋ฐฑ๋ง ๊ฑด์ ๋ฐ์ดํฐ๊ฐ ์๋์ผ๋ก ์ ์ฒ๋ฆฌ๋๊ณ ์๋ค.