์ฝ˜ํ…์ธ  ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ - ๐Ÿ” Elasticsearch: ์ „๋ฌธ ๊ฒ€์ƒ‰ ์—”์ง„ ๊ตฌ์ถ•์œผ๋กœ ๋ฐ์ดํ„ฐ ๊ฒ€์ƒ‰์˜ ์ƒˆ๋กœ์šด ์„ธ๊ณ„๋ฅผ ์—ด๋‹ค

๐Ÿ” Elasticsearch: ์ „๋ฌธ ๊ฒ€์ƒ‰ ์—”์ง„ ๊ตฌ์ถ•์œผ๋กœ ๋ฐ์ดํ„ฐ ๊ฒ€์ƒ‰์˜ ์ƒˆ๋กœ์šด ์„ธ๊ณ„๋ฅผ ์—ด๋‹ค

๋น ๋ฅด๊ณ  ์ •ํ™•ํ•œ ๊ฒ€์ƒ‰ ์‹œ์Šคํ…œ, ์ด์ œ ์ง์ ‘ ๋งŒ๋“ค์–ด๋ณด์ž!

์•ˆ๋…•! ๐Ÿ˜Š ์˜ค๋Š˜์€ ์ •๋ง ์žฌ๋ฏธ์žˆ๋Š” ์ฃผ์ œ๋ฅผ ๊ฐ€์ง€๊ณ  ์™”์–ด. ๋ฐ”๋กœ Elasticsearch๋ผ๋Š” ๋…€์„์ธ๋ฐ, ์ด๊ฒŒ ๋ญ๋ƒ๋ฉด ์šฐ๋ฆฌ๊ฐ€ ๋งค์ผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ์„ ์—„์ฒญ๋‚˜๊ฒŒ ๊ฐ•๋ ฅํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์ฃผ๋Š” ๋„๊ตฌ์•ผ. ๊ตฌ๊ธ€์ฒ˜๋Ÿผ ๋น ๋ฅด๊ณ  ์ •ํ™•ํ•œ ๊ฒ€์ƒ‰ ์‹œ์Šคํ…œ์„ ์ง์ ‘ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค๋ฉด? ์ƒ์ƒ๋งŒ ํ•ด๋„ ๋ฉ‹์ง€์ง€ ์•Š์•„? ๐Ÿš€

์š”์ฆ˜ ๋ฐ์ดํ„ฐ๋Š” ํญ๋ฐœ์ ์œผ๋กœ ์ฆ๊ฐ€ํ•˜๊ณ  ์žˆ์–ด. ์ˆ˜๋ฐฑ๋งŒ, ์ˆ˜์ฒœ๋งŒ ๊ฑด์˜ ๋ฐ์ดํ„ฐ ์†์—์„œ ๋‚ด๊ฐ€ ์›ํ•˜๋Š” ์ •๋ณด๋ฅผ 0.1์ดˆ ๋งŒ์— ์ฐพ์•„๋‚ด๋Š” ๊ฑด ๋งˆ๋ฒ• ๊ฐ™์€ ์ผ์ด์ง€. ๊ทธ๋Ÿฐ๋ฐ Elasticsearch๋Š” ๋ฐ”๋กœ ๊ทธ ๋งˆ๋ฒ•์„ ํ˜„์‹ค๋กœ ๋งŒ๋“ค์–ด์ฃผ๋Š” ๋„๊ตฌ๋ž€๋‹ค! ์ด ๊ธ€์—์„œ๋Š” Elasticsearch๊ฐ€ ๋ญ”์ง€, ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€, ๊ทธ๋ฆฌ๊ณ  ์‹ค์ œ๋กœ ์–ด๋–ป๊ฒŒ ๊ตฌ์ถ•ํ•˜๋Š”์ง€๊นŒ์ง€ ์นœ๊ตฌ์ฒ˜๋Ÿผ ํŽธํ•˜๊ฒŒ ์„ค๋ช…ํ•ด์ค„๊ฒŒ. ์ค€๋น„๋์–ด? ๐ŸŽฏ

๐Ÿ” โšก Elasticsearch Engine ๋น ๋ฅธ ๊ฒ€์ƒ‰์˜ ํ•ต์‹ฌ Query Result

๐ŸŽฏ Elasticsearch๊ฐ€ ๋ญ๊ธธ๋ž˜?

์ž, ๋จผ์ € Elasticsearch๊ฐ€ ์ •ํ™•ํžˆ ๋ญ”์ง€๋ถ€ํ„ฐ ์•Œ์•„๋ณด์ž. ๊ฐ„๋‹จํ•˜๊ฒŒ ๋งํ•˜๋ฉด ์˜คํ”ˆ์†Œ์Šค ๊ธฐ๋ฐ˜์˜ ๋ถ„์‚ฐํ˜• ๊ฒ€์ƒ‰ ๋ฐ ๋ถ„์„ ์—”์ง„์ด์•ผ. ์–ด๋ ต๊ฒŒ ๋“ค๋ฆฌ์ง€? ์‰ฝ๊ฒŒ ํ’€์–ด์„œ ์„ค๋ช…ํ•ด์ค„๊ฒŒ! ๐Ÿค“

์šฐ๋ฆฌ๊ฐ€ ์ผ๋ฐ˜์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค(MySQL, PostgreSQL ๊ฐ™์€)๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋Š” ๋ฐ๋Š” ์ •๋ง ํ›Œ๋ฅญํ•ด. ํ•˜์ง€๋งŒ ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ์—์„œ๋Š” ํ•œ๊ณ„๊ฐ€ ์žˆ์–ด. ํŠนํžˆ ํ…์ŠคํŠธ ๊ฒ€์ƒ‰์ด๋‚˜ ๋ณต์žกํ•œ ์กฐ๊ฑด์˜ ๊ฒ€์ƒ‰์—์„œ๋Š” ์†๋„๊ฐ€ ๋А๋ ค์ง€๊ฑฐ๋‚˜ ์ •ํ™•๋„๊ฐ€ ๋–จ์–ด์งˆ ์ˆ˜ ์žˆ์ง€.

๋ฐ”๋กœ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ํƒ„์ƒํ•œ ๊ฒŒ Elasticsearch์•ผ! ์ด ๋…€์„์€ ๊ฒ€์ƒ‰์— ํŠนํ™”๋˜์–ด ์žˆ์–ด์„œ, ์—„์ฒญ๋‚œ ์–‘์˜ ๋ฐ์ดํ„ฐ ์†์—์„œ๋„ ๋ฒˆ๊ฐœ์ฒ˜๋Ÿผ ๋น ๋ฅด๊ฒŒ ์›ํ•˜๋Š” ์ •๋ณด๋ฅผ ์ฐพ์•„๋‚ผ ์ˆ˜ ์žˆ์–ด. โšก

๐Ÿ’ก Elasticsearch์˜ ํ•ต์‹ฌ ํŠน์ง•

1. ์‹ค์‹œ๊ฐ„ ๊ฒ€์ƒ‰: ๋ฐ์ดํ„ฐ๋ฅผ ์ƒ‰์ธ(Index)ํ•˜๋ฉด ๊ฑฐ์˜ ์ฆ‰์‹œ ๊ฒ€์ƒ‰์ด ๊ฐ€๋Šฅํ•ด
2. ๋ถ„์‚ฐ ์ฒ˜๋ฆฌ: ์—ฌ๋Ÿฌ ์„œ๋ฒ„์— ๋ฐ์ดํ„ฐ๋ฅผ ๋ถ„์‚ฐ์‹œ์ผœ ์ฒ˜๋ฆฌ ์†๋„๋ฅผ ๊ทน๋Œ€ํ™”ํ•ด
3. RESTful API: HTTP ๊ธฐ๋ฐ˜์˜ ๊ฐ„๋‹จํ•œ API๋กœ ๋ˆ„๊ตฌ๋‚˜ ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด
4. ์Šคํ‚ค๋งˆ ํ”„๋ฆฌ: ์—„๊ฒฉํ•œ ์Šคํ‚ค๋งˆ ์—†์ด ์œ ์—ฐํ•˜๊ฒŒ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์žˆ์–ด
5. ์ „๋ฌธ ๊ฒ€์ƒ‰: ์ž์—ฐ์–ด ์ฒ˜๋ฆฌ, ํ˜•ํƒœ์†Œ ๋ถ„์„ ๋“ฑ ๊ณ ๊ธ‰ ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ด

๐ŸŒŸ ์žฌ๋Šฅ๋„ท ํŒ: Elasticsearch ๊ฐ™์€ ์ „๋ฌธ ๊ธฐ์ˆ ์„ ๋ฐฐ์šฐ๊ณ  ์‹ถ๋‹ค๋ฉด ์žฌ๋Šฅ๋„ท(https://www.jaenung.net)์—์„œ ์‹ค๋ฌด ๊ฒฝํ—˜์ด ํ’๋ถ€ํ•œ ์ „๋ฌธ๊ฐ€๋“ค์˜ ๊ฐ•์˜๋ฅผ ์ฐพ์•„๋ณผ ์ˆ˜ ์žˆ์–ด. ์ด๋ก ๋งŒ์œผ๋กœ๋Š” ๋ถ€์กฑํ•œ ์‹ค์ „ ๋…ธํ•˜์šฐ๋ฅผ ๋ฐฐ์šธ ์ˆ˜ ์žˆ๋Š” ์ข‹์€ ๊ธฐํšŒ์ง€!

๐Ÿ—๏ธ Elasticsearch์˜ ๊ธฐ๋ณธ ๊ตฌ์กฐ ์ดํ•ดํ•˜๊ธฐ

Elasticsearch๋ฅผ ์ œ๋Œ€๋กœ ํ™œ์šฉํ•˜๋ ค๋ฉด ๊ธฐ๋ณธ ๊ตฌ์กฐ๋ฅผ ์ดํ•ดํ•˜๋Š” ๊ฒŒ ์ •๋ง ์ค‘์š”ํ•ด. ๋งˆ์น˜ ์ง‘์„ ์ง“๊ธฐ ์ „์— ์„ค๊ณ„๋„๋ฅผ ๋ณด๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ง์ด์•ผ! ํ•˜๋‚˜์”ฉ ์ฐจ๊ทผ์ฐจ๊ทผ ์•Œ์•„๋ณด์ž. ๐Ÿ 

1

ํด๋Ÿฌ์Šคํ„ฐ (Cluster)

ํด๋Ÿฌ์Šคํ„ฐ๋Š” Elasticsearch์˜ ๊ฐ€์žฅ ํฐ ๋‹จ์œ„์•ผ. ํ•˜๋‚˜ ์ด์ƒ์˜ ๋…ธ๋“œ(์„œ๋ฒ„)๊ฐ€ ๋ชจ์—ฌ์„œ ํ•˜๋‚˜์˜ ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ๊ตฌ์„ฑํ•˜์ง€. ํด๋Ÿฌ์Šคํ„ฐ๋Š” ๊ณ ์œ ํ•œ ์ด๋ฆ„์„ ๊ฐ€์ง€๊ณ  ์žˆ๊ณ , ์ด ์ด๋ฆ„์œผ๋กœ ๋…ธ๋“œ๋“ค์ด ์–ด๋А ํด๋Ÿฌ์Šคํ„ฐ์— ์†ํ• ์ง€ ๊ฒฐ์ •๋ผ. ๊ธฐ๋ณธ ์ด๋ฆ„์€ "elasticsearch"์ธ๋ฐ, ์‹ค์ œ ์šด์˜ ํ™˜๊ฒฝ์—์„œ๋Š” ์˜๋ฏธ ์žˆ๋Š” ์ด๋ฆ„์œผ๋กœ ๋ฐ”๊ฟ”์ฃผ๋Š” ๊ฒŒ ์ข‹์•„!

2

๋…ธ๋“œ (Node)

๋…ธ๋“œ๋Š” ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๊ฐœ๋ณ„ ์„œ๋ฒ„์•ผ. ๊ฐ ๋…ธ๋“œ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ณ  ๊ฒ€์ƒ‰ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•ด. ๋…ธ๋“œ๋Š” ์—ฌ๋Ÿฌ ์ข…๋ฅ˜๊ฐ€ ์žˆ๋Š”๋ฐ:

โ€ข Master Node: ํด๋Ÿฌ์Šคํ„ฐ ์ „์ฒด๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๋ฆฌ๋” ๋…ธ๋“œ
โ€ข Data Node: ์‹ค์ œ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ณ  ๊ฒ€์ƒ‰ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋…ธ๋“œ
โ€ข Ingest Node: ๋ฐ์ดํ„ฐ๋ฅผ ์ „์ฒ˜๋ฆฌํ•˜๋Š” ๋…ธ๋“œ
โ€ข Coordinating Node: ํด๋ผ์ด์–ธํŠธ ์š”์ฒญ์„ ๋ฐ›์•„ ์ ์ ˆํ•œ ๋…ธ๋“œ๋กœ ๋ผ์šฐํŒ…ํ•˜๋Š” ๋…ธ๋“œ

3

์ธ๋ฑ์Šค (Index)

์ธ๋ฑ์Šค๋Š” ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ '๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค'์™€ ๋น„์Šทํ•œ ๊ฐœ๋…์ด์•ผ. ๋น„์Šทํ•œ ํŠน์„ฑ์„ ๊ฐ€์ง„ ๋ฌธ์„œ๋“ค์˜ ๋ชจ์Œ์ด์ง€. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋ธ”๋กœ๊ทธ ๊ธ€์„ ์ €์žฅํ•œ๋‹ค๋ฉด "blog_posts"๋ผ๋Š” ์ธ๋ฑ์Šค๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด. ์ธ๋ฑ์Šค ์ด๋ฆ„์€ ๋ฐ˜๋“œ์‹œ ์†Œ๋ฌธ์ž๋กœ ์ž‘์„ฑํ•ด์•ผ ํ•˜๊ณ , ํŠน์ˆ˜๋ฌธ์ž ์‚ฌ์šฉ์— ์ œํ•œ์ด ์žˆ์œผ๋‹ˆ ์ฃผ์˜ํ•ด์•ผ ํ•ด! ๐Ÿ“

4

๋ฌธ์„œ (Document)

๋ฌธ์„œ๋Š” Elasticsearch์—์„œ ์ €์žฅ๋˜๋Š” ๊ธฐ๋ณธ ๋‹จ์œ„์•ผ. JSON ํ˜•์‹์œผ๋กœ ์ €์žฅ๋˜๋ฉฐ, ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ 'ํ–‰(Row)'๊ณผ ๋น„์Šทํ•ด. ๊ฐ ๋ฌธ์„œ๋Š” ๊ณ ์œ ํ•œ ID๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๊ณ , ์—ฌ๋Ÿฌ ํ•„๋“œ(Field)๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ์–ด. ๋ฌธ์„œ๋Š” ์‹ค์ œ๋กœ ๊ฒ€์ƒ‰ํ•˜๊ณ  ์กฐํšŒํ•˜๋Š” ๋ฐ์ดํ„ฐ์˜ ์ตœ์†Œ ๋‹จ์œ„๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋ผ!

5

์ƒค๋“œ (Shard)

์ƒค๋“œ๋Š” ์ธ๋ฑ์Šค๋ฅผ ์—ฌ๋Ÿฌ ์กฐ๊ฐ์œผ๋กœ ๋‚˜๋ˆˆ ๊ฒƒ์ด์•ผ. ์™œ ๋‚˜๋ˆŒ๊นŒ? ๋ฐ์ดํ„ฐ๊ฐ€ ๋„ˆ๋ฌด ๋งŽ์•„์ง€๋ฉด ํ•œ ์„œ๋ฒ„์— ๋‹ค ๋‹ด์„ ์ˆ˜ ์—†์ž–์•„? ๊ทธ๋ž˜์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์—ฌ๋Ÿฌ ์ƒค๋“œ๋กœ ๋‚˜๋ˆ ์„œ ์—ฌ๋Ÿฌ ๋…ธ๋“œ์— ๋ถ„์‚ฐ ์ €์žฅํ•˜๋Š” ๊ฑฐ์•ผ. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๊ฒ€์ƒ‰ ์†๋„๋„ ๋นจ๋ผ์ง€๊ณ , ๋ฐ์ดํ„ฐ ์šฉ๋Ÿ‰ ์ œํ•œ๋„ ์—†์–ด์ ธ! ๐Ÿš€

์ƒค๋“œ์—๋Š” ๋‘ ๊ฐ€์ง€ ์ข…๋ฅ˜๊ฐ€ ์žˆ์–ด:
โ€ข Primary Shard: ์›๋ณธ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ด๊ณ  ์žˆ๋Š” ์ƒค๋“œ
โ€ข Replica Shard: Primary Shard์˜ ๋ณต์‚ฌ๋ณธ์œผ๋กœ, ์žฅ์•  ๋Œ€๋น„์šฉ์ด์•ผ

๊ตฌ์„ฑ์š”์†Œ ์„ค๋ช… ๋น„์œ 
Cluster ์ „์ฒด ์‹œ์Šคํ…œ ๋„์„œ๊ด€ ์ „์ฒด
Node ๊ฐœ๋ณ„ ์„œ๋ฒ„ ๊ฐ๊ฐ์˜ ์„œ๊ฐ€
Index ๋ฐ์ดํ„ฐ ๋ชจ์Œ ํŠน์ • ์ฃผ์ œ์˜ ์ฑ… ๋ชจ์Œ
Document ๊ฐœ๋ณ„ ๋ฐ์ดํ„ฐ ํ•œ ๊ถŒ์˜ ์ฑ…
Shard ๋ฐ์ดํ„ฐ ์กฐ๊ฐ ์ฑ…์˜ ๊ฐ ์ฑ•ํ„ฐ

โš™๏ธ Elasticsearch ์„ค์น˜ํ•˜๊ณ  ์‹œ์ž‘ํ•˜๊ธฐ

์ด์ œ ๋ณธ๊ฒฉ์ ์œผ๋กœ Elasticsearch๋ฅผ ์„ค์น˜ํ•ด๋ณด์ž! ์ƒ๊ฐ๋ณด๋‹ค ์–ด๋ ต์ง€ ์•Š์œผ๋‹ˆ๊นŒ ๊ฑฑ์ •ํ•˜์ง€ ๋งˆ. ์ฐจ๊ทผ์ฐจ๊ทผ ๋”ฐ๋ผ์˜ค๋ฉด ๋ผ! ๐Ÿ˜Š

๐Ÿ“Œ ์‚ฌ์ „ ์ค€๋น„์‚ฌํ•ญ
Elasticsearch๋Š” Java๋กœ ๋งŒ๋“ค์–ด์กŒ๊ธฐ ๋•Œ๋ฌธ์— Java๊ฐ€ ํ•„์š”ํ•ด. Java 8 ์ด์ƒ ๋ฒ„์ „์ด ์„ค์น˜๋˜์–ด ์žˆ์–ด์•ผ ํ•ด. ์ตœ์‹  ๋ฒ„์ „์˜ Elasticsearch๋Š” ์ž์ฒด์ ์œผ๋กœ JDK๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ์–ด์„œ ๋ณ„๋„ ์„ค์น˜๊ฐ€ ํ•„์š” ์—†์„ ์ˆ˜๋„ ์žˆ์–ด!

๐Ÿง Linux/Mac์—์„œ ์„ค์น˜ํ•˜๊ธฐ

ํ„ฐ๋ฏธ๋„ ๋ช…๋ น์–ด
# Elasticsearch ๋‹ค์šด๋กœ๋“œ
wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.11.0-linux-x86_64.tar.gz

# ์••์ถ• ํ•ด์ œ
tar -xzf elasticsearch-8.11.0-linux-x86_64.tar.gz

# ๋””๋ ‰ํ† ๋ฆฌ ์ด๋™
cd elasticsearch-8.11.0

# Elasticsearch ์‹คํ–‰
./bin/elasticsearch

๐ŸชŸ Windows์—์„œ ์„ค์น˜ํ•˜๊ธฐ

Windows์—์„œ๋Š” ZIP ํŒŒ์ผ์„ ๋‹ค์šด๋กœ๋“œํ•ด์„œ ์••์ถ•์„ ํ’€๊ณ , bin ํด๋”์— ์žˆ๋Š” elasticsearch.bat ํŒŒ์ผ์„ ์‹คํ–‰ํ•˜๋ฉด ๋ผ. ์ •๋ง ๊ฐ„๋‹จํ•˜์ง€? ๐Ÿ’ป

Windows ์‹คํ–‰
# ์••์ถ• ํ•ด์ œ ํ›„ bin ํด๋”๋กœ ์ด๋™
cd elasticsearch-8.11.0\bin

# Elasticsearch ์‹คํ–‰
elasticsearch.bat

โœจ ์‹คํ–‰ ํ™•์ธํ•˜๊ธฐ
Elasticsearch๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์‹คํ–‰๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜๋ ค๋ฉด ์›น ๋ธŒ๋ผ์šฐ์ €๋‚˜ curl ๋ช…๋ น์–ด๋กœ http://localhost:9200 ์— ์ ‘์†ํ•ด๋ด. JSON ํ˜•์‹์˜ ์‘๋‹ต์ด ์˜ค๋ฉด ์„ฑ๊ณต์ด์•ผ!

์‹คํ–‰ ํ™•์ธ
curl -X GET "localhost:9200/"

์ •์ƒ์ ์œผ๋กœ ์‹คํ–‰๋˜๋ฉด ์ด๋Ÿฐ ์‘๋‹ต์„ ๋ฐ›์„ ์ˆ˜ ์žˆ์–ด:

์‘๋‹ต ์˜ˆ์‹œ
{
  "name" : "node-1",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "abc123def456",
  "version" : {
    "number" : "8.11.0",
    "build_flavor" : "default",
    "build_type" : "tar",
    "build_hash" : "abc123",
    "build_date" : "2023-11-01T00:00:00.000Z",
    "build_snapshot" : false,
    "lucene_version" : "9.8.0",
    "minimum_wire_compatibility_version" : "7.17.0",
    "minimum_index_compatibility_version" : "7.0.0"
  },
  "tagline" : "You Know, for Search"
}

โš ๏ธ ๋ณด์•ˆ ์ฃผ์˜์‚ฌํ•ญ
Elasticsearch 8.x ๋ฒ„์ „๋ถ€ํ„ฐ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ณด์•ˆ ๊ธฐ๋Šฅ์ด ํ™œ์„ฑํ™”๋˜์–ด ์žˆ์–ด. ์ฒ˜์Œ ์‹คํ–‰ํ•  ๋•Œ ์ž๋™์œผ๋กœ ์ƒ์„ฑ๋˜๋Š” ๋น„๋ฐ€๋ฒˆํ˜ธ์™€ ํ† ํฐ์„ ์ž˜ ๋ณด๊ด€ํ•ด์•ผ ํ•ด. ์‹ค์Šต ํ™˜๊ฒฝ์—์„œ๋Š” ๋ณด์•ˆ์„ ๋น„ํ™œ์„ฑํ™”ํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ, ์šด์˜ ํ™˜๊ฒฝ์—์„œ๋Š” ์ ˆ๋Œ€ ๊ทธ๋Ÿฌ๋ฉด ์•ˆ ๋ผ!

๐Ÿ“Š ์ธ๋ฑ์Šค ์ƒ์„ฑ๊ณผ ๋ฐ์ดํ„ฐ ์ƒ‰์ธํ•˜๊ธฐ

Elasticsearch๊ฐ€ ์‹คํ–‰๋˜์—ˆ์œผ๋‹ˆ ์ด์ œ ๋ณธ๊ฒฉ์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ์–ด๋ณด์ž! ๋จผ์ € ์ธ๋ฑ์Šค๋ฅผ ๋งŒ๋“ค๊ณ , ๊ทธ ์•ˆ์— ๋ฌธ์„œ๋ฅผ ์ €์žฅํ•˜๋Š” ๊ณผ์ •์„ ๋ฐฐ์›Œ๋ณผ๊ฒŒ. ๐ŸŽจ

๐Ÿ“ ์ธ๋ฑ์Šค ์ƒ์„ฑํ•˜๊ธฐ

์ธ๋ฑ์Šค๋ฅผ ๋งŒ๋“œ๋Š” ๊ฑด ์ •๋ง ๊ฐ„๋‹จํ•ด. RESTful API๋ฅผ ์‚ฌ์šฉํ•ด์„œ PUT ์š”์ฒญ์„ ๋ณด๋‚ด๋ฉด ๋ผ. ์˜ˆ๋ฅผ ๋“ค์–ด, ๋ธ”๋กœ๊ทธ ํฌ์ŠคํŠธ๋ฅผ ์ €์žฅํ•  ์ธ๋ฑ์Šค๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž:

์ธ๋ฑ์Šค ์ƒ์„ฑ API
PUT /blog_posts
{
  "settings": {
    "number_of_shards": 3,
    "number_of_replicas": 1
  },
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "standard"
      },
      "content": {
        "type": "text",
        "analyzer": "standard"
      },
      "author": {
        "type": "keyword"
      },
      "published_date": {
        "type": "date"
      },
      "tags": {
        "type": "keyword"
      },
      "views": {
        "type": "integer"
      }
    }
  }
}

์œ„ ์ฝ”๋“œ๋ฅผ ํ•˜๋‚˜์”ฉ ๋œฏ์–ด๋ณด์ž:

โ€ข settings: ์ธ๋ฑ์Šค์˜ ์„ค์ •์„ ์ •์˜ํ•ด. ์ƒค๋“œ ๊ฐœ์ˆ˜์™€ ๋ณต์ œ๋ณธ ๊ฐœ์ˆ˜๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์–ด
โ€ข mappings: ๋ฌธ์„œ์˜ ๊ตฌ์กฐ๋ฅผ ์ •์˜ํ•ด. ๊ฐ ํ•„๋“œ์˜ ๋ฐ์ดํ„ฐ ํƒ€์ž…์„ ์ง€์ •ํ•˜์ง€
โ€ข properties: ์‹ค์ œ ํ•„๋“œ๋“ค์„ ์ •์˜ํ•˜๋Š” ๋ถ€๋ถ„์ด์•ผ

๐Ÿ”ค ์ฃผ์š” ๋ฐ์ดํ„ฐ ํƒ€์ž…

text: ์ „๋ฌธ ๊ฒ€์ƒ‰์ด ๊ฐ€๋Šฅํ•œ ํ…์ŠคํŠธ (๋ถ„์„๋จ)
keyword: ์ •ํ™•ํžˆ ์ผ์น˜ํ•˜๋Š” ๊ฒ€์ƒ‰์šฉ ํ…์ŠคํŠธ (๋ถ„์„ ์•ˆ ๋จ)
date: ๋‚ ์งœ/์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ
integer/long: ์ •์ˆ˜ํ˜• ์ˆซ์ž
float/double: ์‹ค์ˆ˜ํ˜• ์ˆซ์ž
boolean: true/false ๊ฐ’
object: ์ค‘์ฒฉ๋œ JSON ๊ฐ์ฒด
nested: ๋ฐฐ์—ด ํ˜•ํƒœ์˜ ๋ณต์žกํ•œ ๊ฐ์ฒด

๐Ÿ“ฅ ๋ฌธ์„œ ์ƒ‰์ธํ•˜๊ธฐ

์ด์ œ ์‹ค์ œ ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ์–ด๋ณด์ž! ๋ฌธ์„œ๋ฅผ ์ƒ‰์ธํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ํฌ๊ฒŒ ๋‘ ๊ฐ€์ง€๊ฐ€ ์žˆ์–ด:

๋ฐฉ๋ฒ• 1: ID๋ฅผ ์ง์ ‘ ์ง€์ •ํ•˜๊ธฐ

๋ฌธ์„œ ์ƒ‰์ธ (ID ์ง€์ •)
PUT /blog_posts/_doc/1
{
  "title": "Elasticsearch ์‹œ์ž‘ํ•˜๊ธฐ",
  "content": "Elasticsearch๋Š” ๊ฐ•๋ ฅํ•œ ๊ฒ€์ƒ‰ ์—”์ง„์ž…๋‹ˆ๋‹ค. ์ด ๊ธ€์—์„œ๋Š” ๊ธฐ๋ณธ ๊ฐœ๋…๋ถ€ํ„ฐ ์‹ค์ „ ํ™œ์šฉ๊นŒ์ง€ ๋‹ค๋ฃน๋‹ˆ๋‹ค.",
  "author": "๊น€๊ฐœ๋ฐœ",
  "published_date": "2024-01-15",
  "tags": ["elasticsearch", "๊ฒ€์ƒ‰์—”์ง„", "๋น…๋ฐ์ดํ„ฐ"],
  "views": 1250
}

๋ฐฉ๋ฒ• 2: ID ์ž๋™ ์ƒ์„ฑํ•˜๊ธฐ

๋ฌธ์„œ ์ƒ‰์ธ (ID ์ž๋™)
POST /blog_posts/_doc
{
  "title": "์‹ค์ „ Elasticsearch ํ™œ์šฉ๋ฒ•",
  "content": "์‹ค๋ฌด์—์„œ Elasticsearch๋ฅผ ์–ด๋–ป๊ฒŒ ํ™œ์šฉํ•˜๋Š”์ง€ ๊ตฌ์ฒด์ ์ธ ์˜ˆ์ œ์™€ ํ•จ๊ป˜ ์•Œ์•„๋ด…๋‹ˆ๋‹ค.",
  "author": "๋ฐ•๋ฐ์ดํ„ฐ",
  "published_date": "2024-01-16",
  "tags": ["elasticsearch", "์‹ค์ „", "ํŠœํ† ๋ฆฌ์–ผ"],
  "views": 890
}

๐Ÿ’ก PUT vs POST
PUT์€ ID๋ฅผ ์ง์ ‘ ์ง€์ •ํ•  ๋•Œ ์‚ฌ์šฉํ•˜๊ณ , POST๋Š” Elasticsearch๊ฐ€ ์ž๋™์œผ๋กœ ID๋ฅผ ์ƒ์„ฑํ•˜๊ฒŒ ํ•  ๋•Œ ์‚ฌ์šฉํ•ด. PUT์€ ๊ฐ™์€ ID๋กœ ๋‹ค์‹œ ์š”์ฒญํ•˜๋ฉด ๊ธฐ์กด ๋ฌธ์„œ๋ฅผ ๋ฎ์–ด์“ฐ์ง€๋งŒ, POST๋Š” ํ•ญ์ƒ ์ƒˆ๋กœ์šด ๋ฌธ์„œ๋ฅผ ์ƒ์„ฑํ•ด!

๐Ÿ”„ ๋Œ€๋Ÿ‰ ๋ฐ์ดํ„ฐ ์ƒ‰์ธํ•˜๊ธฐ (Bulk API)

ํ•œ ๋ฒˆ์— ์—ฌ๋Ÿฌ ๋ฌธ์„œ๋ฅผ ์ƒ‰์ธํ•ด์•ผ ํ•  ๋•Œ๋Š” Bulk API๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ›จ์”ฌ ํšจ์œจ์ ์ด์•ผ. ๋„คํŠธ์›Œํฌ ์˜ค๋ฒ„ํ—ค๋“œ๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ๊ฑฐ๋“ ! ๐Ÿ’ช

Bulk API ์‚ฌ์šฉ
POST /blog_posts/_bulk
{"index":{"_id":"2"}}
{"title":"Elasticsearch ์„ฑ๋Šฅ ์ตœ์ ํ™”","content":"๋Œ€์šฉ๋Ÿ‰ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ ์„ฑ๋Šฅ ์ตœ์ ํ™” ๊ธฐ๋ฒ•","author":"์ด์„ฑ๋Šฅ","published_date":"2024-01-17","tags":["์„ฑ๋Šฅ","์ตœ์ ํ™”"],"views":2100}
{"index":{"_id":"3"}}
{"title":"Elasticsearch ๋ณด์•ˆ ์„ค์ •","content":"์šด์˜ ํ™˜๊ฒฝ์—์„œ ํ•„์ˆ˜์ ์ธ ๋ณด์•ˆ ์„ค์ • ๋ฐฉ๋ฒ•","author":"์ตœ๋ณด์•ˆ","published_date":"2024-01-18","tags":["๋ณด์•ˆ","์šด์˜"],"views":1580}
{"index":{"_id":"4"}}
{"title":"Elasticsearch ํด๋Ÿฌ์Šคํ„ฐ ๊ตฌ์ถ•","content":"๊ณ ๊ฐ€์šฉ์„ฑ์„ ์œ„ํ•œ ํด๋Ÿฌ์Šคํ„ฐ ๊ตฌ์ถ• ๊ฐ€์ด๋“œ","author":"์ •ํด๋Ÿฌ์Šคํ„ฐ","published_date":"2024-01-19","tags":["ํด๋Ÿฌ์Šคํ„ฐ","๊ณ ๊ฐ€์šฉ์„ฑ"],"views":1920}

Bulk API๋Š” ํ•œ ์ค„์— ๋ช…๋ น์–ด, ๋‹ค์Œ ์ค„์— ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ๋Š” ํ˜•์‹์ด์•ผ. ์ฃผ์˜ํ•  ์ ์€ ๋งˆ์ง€๋ง‰์— ๋ฐ˜๋“œ์‹œ ์ค„๋ฐ”๊ฟˆ์ด ์žˆ์–ด์•ผ ํ•œ๋‹ค๋Š” ๊ฑฐ! ๐ŸŽฏ

๐Ÿ” ๊ฒ€์ƒ‰ ์ฟผ๋ฆฌ ๋งˆ์Šคํ„ฐํ•˜๊ธฐ

๋“œ๋””์–ด ๊ฐ€์žฅ ์žฌ๋ฏธ์žˆ๋Š” ๋ถ€๋ถ„์ด์•ผ! ๊ฒ€์ƒ‰ ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ฐฐ์›Œ๋ณด์ž. Elasticsearch์˜ ์ง„์ •ํ•œ ํž˜์€ ๋ฐ”๋กœ ์—ฌ๊ธฐ์— ์žˆ์–ด! โšก

๐ŸŽฏ ๊ธฐ๋ณธ ๊ฒ€์ƒ‰ (Match Query)

๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ๊ฒ€์ƒ‰ ๋ฐฉ๋ฒ•์€ Match Query์•ผ. ํŠน์ • ํ•„๋“œ์—์„œ ํ‚ค์›Œ๋“œ๋ฅผ ๊ฒ€์ƒ‰ํ•  ๋•Œ ์‚ฌ์šฉํ•ด:

Match Query
GET /blog_posts/_search
{
  "query": {
    "match": {
      "content": "๊ฒ€์ƒ‰ ์—”์ง„"
    }
  }
}

์ด ์ฟผ๋ฆฌ๋Š” content ํ•„๋“œ์—์„œ "๊ฒ€์ƒ‰" ๋˜๋Š” "์—”์ง„"์ด๋ผ๋Š” ๋‹จ์–ด๊ฐ€ ํฌํ•จ๋œ ๋ชจ๋“  ๋ฌธ์„œ๋ฅผ ์ฐพ์•„์ค˜. Elasticsearch๋Š” ์ž๋™์œผ๋กœ ํ…์ŠคํŠธ๋ฅผ ๋ถ„์„ํ•ด์„œ ๊ฒ€์ƒ‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ •ํ™•ํžˆ ์ผ์น˜ํ•˜์ง€ ์•Š์•„๋„ ๊ด€๋ จ ๋ฌธ์„œ๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ์–ด! ๐ŸŽจ

๐ŸŽช ๋ณตํ•ฉ ๊ฒ€์ƒ‰ (Bool Query)

์‹ค์ œ ์„œ๋น„์Šค์—์„œ๋Š” ์—ฌ๋Ÿฌ ์กฐ๊ฑด์„ ์กฐํ•ฉํ•ด์„œ ๊ฒ€์ƒ‰ํ•ด์•ผ ํ•  ๋•Œ๊ฐ€ ๋งŽ์•„. ์ด๋Ÿด ๋•Œ Bool Query๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ผ:

Bool Query
GET /blog_posts/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "content": "elasticsearch"
          }
        }
      ],
      "filter": [
        {
          "range": {
            "views": {
              "gte": 1000
            }
          }
        }
      ],
      "should": [
        {
          "match": {
            "tags": "์‹ค์ „"
          }
        }
      ],
      "must_not": [
        {
          "match": {
            "author": "ํ…Œ์ŠคํŠธ"
          }
        }
      ]
    }
  }
}

๐Ÿ”ง Bool Query ๊ตฌ์„ฑ์š”์†Œ

must: ๋ฐ˜๋“œ์‹œ ์ผ์น˜ํ•ด์•ผ ํ•˜๋Š” ์กฐ๊ฑด (AND ์—ฐ์‚ฐ, ์ ์ˆ˜์— ์˜ํ–ฅ)
filter: ๋ฐ˜๋“œ์‹œ ์ผ์น˜ํ•ด์•ผ ํ•˜์ง€๋งŒ ์ ์ˆ˜์—๋Š” ์˜ํ–ฅ ์—†์Œ (์„ฑ๋Šฅ ์ข‹์Œ)
should: ์ผ์น˜ํ•˜๋ฉด ์ข‹์€ ์กฐ๊ฑด (OR ์—ฐ์‚ฐ, ์ ์ˆ˜ ํ–ฅ์ƒ)
must_not: ์ผ์น˜ํ•˜๋ฉด ์•ˆ ๋˜๋Š” ์กฐ๊ฑด (NOT ์—ฐ์‚ฐ)

๐ŸŽฏ ์ •ํ™•ํ•œ ๊ฒ€์ƒ‰ (Term Query)

keyword ํƒ€์ž… ํ•„๋“œ์—์„œ ์ •ํ™•ํžˆ ์ผ์น˜ํ•˜๋Š” ๊ฐ’์„ ์ฐพ์„ ๋•Œ๋Š” Term Query๋ฅผ ์‚ฌ์šฉํ•ด:

Term Query
GET /blog_posts/_search
{
  "query": {
    "term": {
      "author": "๊น€๊ฐœ๋ฐœ"
    }
  }
}

๐Ÿ“Š ๋ฒ”์œ„ ๊ฒ€์ƒ‰ (Range Query)

๋‚ ์งœ๋‚˜ ์ˆซ์ž ๋ฒ”์œ„๋กœ ๊ฒ€์ƒ‰ํ•  ๋•Œ๋Š” Range Query๊ฐ€ ์œ ์šฉํ•ด:

Range Query
GET /blog_posts/_search
{
  "query": {
    "range": {
      "published_date": {
        "gte": "2024-01-01",
        "lte": "2024-01-31"
      }
    }
  }
}

๐Ÿ“… Range Query ์—ฐ์‚ฐ์ž
gte: ํฌ๊ฑฐ๋‚˜ ๊ฐ™์Œ (Greater Than or Equal)
gt: ํผ (Greater Than)
lte: ์ž‘๊ฑฐ๋‚˜ ๊ฐ™์Œ (Less Than or Equal)
lt: ์ž‘์Œ (Less Than)

๐ŸŒŸ ์™€์ผ๋“œ์นด๋“œ ๊ฒ€์ƒ‰ (Wildcard Query)

๋ถ€๋ถ„ ์ผ์น˜ ๊ฒ€์ƒ‰์ด ํ•„์š”ํ•  ๋•Œ๋Š” Wildcard Query๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด. ํ•˜์ง€๋งŒ ์„ฑ๋Šฅ์ด ์ข‹์ง€ ์•Š์œผ๋‹ˆ ๊ผญ ํ•„์š”ํ•  ๋•Œ๋งŒ ์‚ฌ์šฉํ•˜๋Š” ๊ฒŒ ์ข‹์•„!

Wildcard Query
GET /blog_posts/_search
{
  "query": {
    "wildcard": {
      "title": "*elastic*"
    }
  }
}

๐ŸŽจ ํผ์ง€ ๊ฒ€์ƒ‰ (Fuzzy Query)

์˜คํƒ€๊ฐ€ ์žˆ์–ด๋„ ๊ฒ€์ƒ‰ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๊ฒŒ Fuzzy Query์•ผ. ์‚ฌ์šฉ์ž๊ฐ€ ์ฒ ์ž๋ฅผ ํ‹€๋ ค๋„ ์›ํ•˜๋Š” ๊ฒฐ๊ณผ๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ์–ด! ๐Ÿ˜Š

Fuzzy Query
GET /blog_posts/_search
{
  "query": {
    "fuzzy": {
      "title": {
        "value": "elasticsarch",
        "fuzziness": "AUTO"
      }
    }
  }
}

"elasticsarch"๋ผ๊ณ  ์ž˜๋ชป ์ž…๋ ฅํ•ด๋„ "elasticsearch"๋ฅผ ์ฐพ์•„์ค˜! fuzziness ๊ฐ’์€ ํ—ˆ์šฉํ•  ํŽธ์ง‘ ๊ฑฐ๋ฆฌ๋ฅผ ์˜๋ฏธํ•˜๋Š”๋ฐ, "AUTO"๋กœ ์„ค์ •ํ•˜๋ฉด Elasticsearch๊ฐ€ ์ž๋™์œผ๋กœ ์ ์ ˆํ•œ ๊ฐ’์„ ์„ ํƒํ•ด์ค˜. ๐ŸŽฏ

๊ฒ€์ƒ‰์–ด๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”... ๐Ÿ” โœ“ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ 1 Elasticsearch ์™„๋ฒฝ ๊ฐ€์ด๋“œ ๊ฒ€์ƒ‰ ์—”์ง„ ๊ตฌ์ถ•์˜ ๋ชจ๋“  ๊ฒƒ ๊ด€๋ จ๋„: 95% โœ“ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ 2 ์‹ค์ „ ๊ฒ€์ƒ‰ ์‹œ์Šคํ…œ ๊ตฌ์ถ• ๋Œ€์šฉ๋Ÿ‰ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ๊ธฐ๋ฒ• ๊ด€๋ จ๋„: 87% โœ“ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ 3 ๊ฒ€์ƒ‰ ์—”์ง„ ์ตœ์ ํ™” ํŒ ์„ฑ๋Šฅ ํ–ฅ์ƒ ์ „๋žต ๊ด€๋ จ๋„: 78% โšก 0.023์ดˆ ๋งŒ์— 1,234,567๊ฐœ ๋ฌธ์„œ ๊ฒ€์ƒ‰ ์™„๋ฃŒ

๐Ÿ“ˆ ์ง‘๊ณ„์™€ ๋ถ„์„ (Aggregations)

Elasticsearch๋Š” ๋‹จ์ˆœํžˆ ๊ฒ€์ƒ‰๋งŒ ํ•˜๋Š” ๊ฒŒ ์•„๋‹ˆ์•ผ. ๋ฐ์ดํ„ฐ๋ฅผ ๋ถ„์„ํ•˜๊ณ  ํ†ต๊ณ„๋ฅผ ๋‚ด๋Š” ๊ฐ•๋ ฅํ•œ ์ง‘๊ณ„(Aggregation) ๊ธฐ๋Šฅ๋„ ์ œ๊ณตํ•ด! ์ด๊ฑด ์ •๋ง ์œ ์šฉํ•œ ๊ธฐ๋Šฅ์ด์•ผ. ๐Ÿ“Š

๐Ÿ“Š ๋ฉ”ํŠธ๋ฆญ ์ง‘๊ณ„ (Metric Aggregations)

์ˆซ์ž ๋ฐ์ดํ„ฐ์˜ ํ†ต๊ณ„๋ฅผ ๊ณ„์‚ฐํ•  ๋•Œ ์‚ฌ์šฉํ•ด. ํ‰๊ท , ํ•ฉ๊ณ„, ์ตœ๋Œ€๊ฐ’, ์ตœ์†Œ๊ฐ’ ๋“ฑ์„ ๊ตฌํ•  ์ˆ˜ ์žˆ์–ด:

ํ‰๊ท  ์กฐํšŒ์ˆ˜ ๊ณ„์‚ฐ
GET /blog_posts/_search
{
  "size": 0,
  "aggs": {
    "avg_views": {
      "avg": {
        "field": "views"
      }
    },
    "max_views": {
      "max": {
        "field": "views"
      }
    },
    "min_views": {
      "min": {
        "field": "views"
      }
    },
    "total_views": {
      "sum": {
        "field": "views"
      }
    }
  }
}

"size": 0์œผ๋กœ ์„ค์ •ํ•˜๋ฉด ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๋Š” ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š๊ณ  ์ง‘๊ณ„ ๊ฒฐ๊ณผ๋งŒ ๋ฐ›์„ ์ˆ˜ ์žˆ์–ด. ๋ถˆํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ ์ „์†ก์„ ์ค„์ผ ์ˆ˜ ์žˆ์ง€! ๐Ÿ’ก

๐Ÿ—‚๏ธ ๋ฒ„ํ‚ท ์ง‘๊ณ„ (Bucket Aggregations)

๋ฐ์ดํ„ฐ๋ฅผ ๊ทธ๋ฃน์œผ๋กœ ๋‚˜๋ˆ ์„œ ๋ถ„์„ํ•  ๋•Œ ์‚ฌ์šฉํ•ด. ์˜ˆ๋ฅผ ๋“ค์–ด, ์ž‘์„ฑ์ž๋ณ„๋กœ ๊ธ€ ๊ฐœ์ˆ˜๋ฅผ ์„ธ๊ฑฐ๋‚˜, ๋‚ ์งœ๋ณ„๋กœ ํ†ต๊ณ„๋ฅผ ๋‚ผ ์ˆ˜ ์žˆ์–ด:

์ž‘์„ฑ์ž๋ณ„ ๊ธ€ ๊ฐœ์ˆ˜
GET /blog_posts/_search
{
  "size": 0,
  "aggs": {
    "posts_by_author": {
      "terms": {
        "field": "author",
        "size": 10
      },
      "aggs": {
        "avg_views_per_author": {
          "avg": {
            "field": "views"
          }
        }
      }
    }
  }
}

์ด ์ฟผ๋ฆฌ๋Š” ์ž‘์„ฑ์ž๋ณ„๋กœ ๊ธ€ ๊ฐœ์ˆ˜๋ฅผ ์„ธ๊ณ , ๊ฐ ์ž‘์„ฑ์ž์˜ ํ‰๊ท  ์กฐํšŒ์ˆ˜๋„ ํ•จ๊ป˜ ๊ณ„์‚ฐํ•ด์ค˜. ์ง‘๊ณ„ ์•ˆ์— ์ง‘๊ณ„๋ฅผ ์ค‘์ฒฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒŒ ์ •๋ง ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ์ด์•ผ! ๐Ÿš€

๐Ÿ“… ๋‚ ์งœ ํžˆ์Šคํ† ๊ทธ๋žจ

์‹œ๊ฐ„๋Œ€๋ณ„ ํ†ต๊ณ„๋ฅผ ๋ณด๊ณ  ์‹ถ์„ ๋•Œ๋Š” Date Histogram์„ ์‚ฌ์šฉํ•ด:

์›”๋ณ„ ๊ฒŒ์‹œ๊ธ€ ํ†ต๊ณ„
GET /blog_posts/_search
{
  "size": 0,
  "aggs": {
    "posts_over_time": {
      "date_histogram": {
        "field": "published_date",
        "calendar_interval": "month",
        "format": "yyyy-MM"
      },
      "aggs": {
        "total_views": {
          "sum": {
            "field": "views"
          }
        }
      }
    }
  }
}

๐ŸŽฏ ์ง‘๊ณ„ ํ™œ์šฉ ํŒ
์ง‘๊ณ„๋Š” ์‹ค์‹œ๊ฐ„ ๋Œ€์‹œ๋ณด๋“œ๋‚˜ ๋ถ„์„ ๋ฆฌํฌํŠธ๋ฅผ ๋งŒ๋“ค ๋•Œ ์ •๋ง ์œ ์šฉํ•ด. ์˜ˆ๋ฅผ ๋“ค์–ด, ์ „์ž์ƒ๊ฑฐ๋ž˜ ์‚ฌ์ดํŠธ์—์„œ ์ผ๋ณ„ ๋งค์ถœ ํ†ต๊ณ„, ์ธ๊ธฐ ์ƒํ’ˆ ์ˆœ์œ„, ์ง€์—ญ๋ณ„ ํŒ๋งค๋Ÿ‰ ๋“ฑ์„ ์‹ค์‹œ๊ฐ„์œผ๋กœ ํ™•์ธํ•  ์ˆ˜ ์žˆ์–ด!

๐ŸŽจ ํ•œ๊ธ€ ๊ฒ€์ƒ‰ ์ตœ์ ํ™”ํ•˜๊ธฐ

ํ•œ๊ธ€ ๊ฒ€์ƒ‰์€ ์˜์–ด์™€ ๋‹ฌ๋ฆฌ ํŠน๋ณ„ํ•œ ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•ด. ํ˜•ํƒœ์†Œ ๋ถ„์„์ด ์ค‘์š”ํ•˜๊ฑฐ๋“ ! ์˜ˆ๋ฅผ ๋“ค์–ด, "๋จน์—ˆ๋‹ค", "๋จน๋Š”๋‹ค", "๋จน์„"์€ ๋ชจ๋‘ "๋จน๋‹ค"๋ผ๋Š” ๊ธฐ๋ณธํ˜•์œผ๋กœ ๋ถ„์„๋˜์–ด์•ผ ์ œ๋Œ€๋กœ ๊ฒ€์ƒ‰์ด ๋ผ. ๐Ÿ‡ฐ๐Ÿ‡ท

๐Ÿ”ง Nori ๋ถ„์„๊ธฐ ์„ค์น˜

Elasticsearch์—์„œ ํ•œ๊ธ€ ํ˜•ํƒœ์†Œ ๋ถ„์„์„ ์œ„ํ•ด Nori ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์ œ๊ณตํ•ด. ์„ค์น˜๋Š” ์ •๋ง ๊ฐ„๋‹จํ•ด:

Nori ํ”Œ๋Ÿฌ๊ทธ์ธ ์„ค์น˜
# Elasticsearch ๋””๋ ‰ํ† ๋ฆฌ์—์„œ ์‹คํ–‰
./bin/elasticsearch-plugin install analysis-nori

# ์„ค์น˜ ํ™•์ธ
./bin/elasticsearch-plugin list

ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์„ค์น˜ํ•œ ํ›„์—๋Š” Elasticsearch๋ฅผ ์žฌ์‹œ์ž‘ํ•ด์•ผ ํ•ด!

๐Ÿ“ ํ•œ๊ธ€ ์ธ๋ฑ์Šค ์„ค์ •

Nori ๋ถ„์„๊ธฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ธ๋ฑ์Šค๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž:

ํ•œ๊ธ€ ์ตœ์ ํ™” ์ธ๋ฑ์Šค
PUT /korean_blog
{
  "settings": {
    "analysis": {
      "tokenizer": {
        "nori_user_dict": {
          "type": "nori_tokenizer",
          "decompound_mode": "mixed",
          "user_dictionary": "userdict_ko.txt"
        }
      },
      "analyzer": {
        "korean": {
          "type": "custom",
          "tokenizer": "nori_user_dict",
          "filter": ["lowercase", "nori_part_of_speech"]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "korean"
      },
      "content": {
        "type": "text",
        "analyzer": "korean"
      }
    }
  }
}

๐Ÿ” Nori ๋ถ„์„ ๋ชจ๋“œ

none: ๋ณตํ•ฉ์–ด๋ฅผ ๋ถ„ํ•ดํ•˜์ง€ ์•Š์Œ
discard: ๋ณตํ•ฉ์–ด๋งŒ ์ €์žฅ (์›๋ณธ ๋‹จ์–ด ๋ฒ„๋ฆผ)
mixed: ๋ณตํ•ฉ์–ด์™€ ๋ถ„ํ•ด๋œ ๋‹จ์–ด ๋ชจ๋‘ ์ €์žฅ (์ถ”์ฒœ!)

๐Ÿงช ๋ถ„์„๊ธฐ ํ…Œ์ŠคํŠธ

๋ถ„์„๊ธฐ๊ฐ€ ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜๋Š”์ง€ ํ…Œ์ŠคํŠธํ•ด๋ณผ ์ˆ˜ ์žˆ์–ด:

๋ถ„์„๊ธฐ ํ…Œ์ŠคํŠธ
POST /korean_blog/_analyze
{
  "analyzer": "korean",
  "text": "Elasticsearch๋กœ ํ•œ๊ธ€ ๊ฒ€์ƒ‰ ์—”์ง„์„ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค"
}

์ด ์š”์ฒญ์„ ๋ณด๋‚ด๋ฉด ํ…์ŠคํŠธ๊ฐ€ ์–ด๋–ป๊ฒŒ ํ† ํฐ์œผ๋กœ ๋ถ„ํ•ด๋˜๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ์–ด. ํ˜•ํƒœ์†Œ ๋ถ„์„ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ฉด์„œ ๊ฒ€์ƒ‰ ํ’ˆ์งˆ์„ ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ์ง€! ๐ŸŽฏ

โšก ์„ฑ๋Šฅ ์ตœ์ ํ™” ์ „๋žต

Elasticsearch๋ฅผ ์‹ค์ œ ์„œ๋น„์Šค์— ์ ์šฉํ•˜๋ ค๋ฉด ์„ฑ๋Šฅ ์ตœ์ ํ™”๊ฐ€ ์ •๋ง ์ค‘์š”ํ•ด. ๋ช‡ ๊ฐ€์ง€ ํ•ต์‹ฌ ์ „๋žต์„ ์•Œ๋ ค์ค„๊ฒŒ! ๐Ÿ’ช

๐ŸŽฏ ์ƒค๋“œ ๊ฐœ์ˆ˜ ์ตœ์ ํ™”

์ƒค๋“œ ๊ฐœ์ˆ˜๋Š” ์„ฑ๋Šฅ์— ํฐ ์˜ํ–ฅ์„ ๋ฏธ์ณ. ๋„ˆ๋ฌด ๋งŽ์œผ๋ฉด ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ๋ฐœ์ƒํ•˜๊ณ , ๋„ˆ๋ฌด ์ ์œผ๋ฉด ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ์˜ ์ด์ ์„ ๋ชป ์‚ด๋ ค. ์ผ๋ฐ˜์ ์ธ ๊ฐ€์ด๋“œ๋ผ์ธ์€:

๐Ÿ“Š ์ƒค๋“œ ๊ฐœ์ˆ˜ ๊ฐ€์ด๋“œ๋ผ์ธ

โ€ข ๊ฐ ์ƒค๋“œ์˜ ํฌ๊ธฐ๋Š” 20GB~50GB ์ •๋„๊ฐ€ ์ ๋‹นํ•ด
โ€ข ๋…ธ๋“œ๋‹น ์ƒค๋“œ ๊ฐœ์ˆ˜๋Š” 20๊ฐœ ์ดํ•˜๋กœ ์œ ์ง€ํ•˜๋Š” ๊ฒŒ ์ข‹์•„
โ€ข ์ž‘์€ ์ธ๋ฑ์Šค๋Š” ์ƒค๋“œ 1๊ฐœ๋กœ ์‹œ์ž‘ํ•ด๋„ ์ถฉ๋ถ„ํ•ด
โ€ข ๋ฐ์ดํ„ฐ๊ฐ€ ์ฆ๊ฐ€ํ•˜๋ฉด Reindex API๋กœ ์ƒค๋“œ ๊ฐœ์ˆ˜๋ฅผ ์กฐ์ •ํ•  ์ˆ˜ ์žˆ์–ด

๐Ÿ’พ ๋ฉ”๋ชจ๋ฆฌ ์„ค์ •

Elasticsearch๋Š” ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด์•ผ. JVM ํž™ ๋ฉ”๋ชจ๋ฆฌ ์„ค์ •์ด ์ค‘์š”ํ•ด:

jvm.options ์„ค์ •
# ํž™ ๋ฉ”๋ชจ๋ฆฌ ์„ค์ • (์ตœ์†Œ๊ฐ’๊ณผ ์ตœ๋Œ€๊ฐ’์„ ๋™์ผํ•˜๊ฒŒ)
-Xms4g
-Xmx4g

# ์ฃผ์˜: ์ „์ฒด ๋ฉ”๋ชจ๋ฆฌ์˜ 50%๋ฅผ ๋„˜์ง€ ์•Š๋„๋ก!
# ๋‚˜๋จธ์ง€ 50%๋Š” OS ํŒŒ์ผ ์บ์‹œ์šฉ์œผ๋กœ ๋‚จ๊ฒจ๋‘ฌ์•ผ ํ•ด

โš ๏ธ ์ค‘์š”ํ•œ ๋ฉ”๋ชจ๋ฆฌ ๊ทœ์น™
ํž™ ๋ฉ”๋ชจ๋ฆฌ๋Š” ์ ˆ๋Œ€ 32GB๋ฅผ ๋„˜๊ธฐ๋ฉด ์•ˆ ๋ผ! 32GB๋ฅผ ๋„˜์œผ๋ฉด JVM์˜ Compressed OOPs ์ตœ์ ํ™”๊ฐ€ ๋น„ํ™œ์„ฑํ™”๋˜์–ด ์˜คํžˆ๋ ค ์„ฑ๋Šฅ์ด ๋–จ์–ด์ ธ. ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ๋งŽ์ด ํ•„์š”ํ•˜๋ฉด ๋…ธ๋“œ๋ฅผ ์—ฌ๋Ÿฌ ๊ฐœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒŒ ๋‚˜์•„!

๐Ÿ”„ Refresh Interval ์กฐ์ •

Elasticsearch๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ 1์ดˆ๋งˆ๋‹ค ์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ๋ฅผ ๊ฒ€์ƒ‰ ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋งŒ๋“ค์–ด(refresh). ํ•˜์ง€๋งŒ ๋Œ€๋Ÿ‰ ์ƒ‰์ธ ์ž‘์—…์„ ํ•  ๋•Œ๋Š” ์ด ๊ฐ„๊ฒฉ์„ ๋Š˜๋ฆฌ๋ฉด ์„ฑ๋Šฅ์ด ํฌ๊ฒŒ ํ–ฅ์ƒ๋ผ:

Refresh Interval ์กฐ์ •
# ๋Œ€๋Ÿ‰ ์ƒ‰์ธ ์‹œ์ž‘ ์ „
PUT /blog_posts/_settings
{
  "index": {
    "refresh_interval": "-1"
  }
}

# ๋Œ€๋Ÿ‰ ์ƒ‰์ธ ์ž‘์—… ์ˆ˜ํ–‰...

# ์ž‘์—… ์™„๋ฃŒ ํ›„ ์›๋ž˜๋Œ€๋กœ
PUT /blog_posts/_settings
{
  "index": {
    "refresh_interval": "1s"
  }
}

# ์ˆ˜๋™์œผ๋กœ refresh
POST /blog_posts/_refresh

๐ŸŽจ ํ•„๋“œ ์ €์žฅ ์ตœ์ ํ™”

๋ชจ๋“  ํ•„๋“œ๋ฅผ ์ €์žฅํ•  ํ•„์š”๋Š” ์—†์–ด. ๊ฒ€์ƒ‰๋งŒ ํ•˜๊ณ  ์›๋ณธ ๋ฐ์ดํ„ฐ๋Š” ํ•„์š” ์—†๋‹ค๋ฉด _source๋ฅผ ๋น„ํ™œ์„ฑํ™”ํ•  ์ˆ˜ ์žˆ์–ด:

_source ๋น„ํ™œ์„ฑํ™”
PUT /logs
{
  "mappings": {
    "_source": {
      "enabled": false
    },
    "properties": {
      "message": {
        "type": "text",
        "store": true
      },
      "timestamp": {
        "type": "date",
        "store": true
      }
    }
  }
}

ํ•˜์ง€๋งŒ ์ฃผ์˜ํ•ด! _source๋ฅผ ๋น„ํ™œ์„ฑํ™”ํ•˜๋ฉด ๋ฌธ์„œ ์—…๋ฐ์ดํŠธ๋‚˜ reindex๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•ด์ ธ. ์‹ ์ค‘ํ•˜๊ฒŒ ๊ฒฐ์ •ํ•ด์•ผ ํ•ด! ๐Ÿค”

๐Ÿ” ๊ฒ€์ƒ‰ ์ฟผ๋ฆฌ ์ตœ์ ํ™”

1. Filter Context ํ™œ์šฉ

์ ์ˆ˜ ๊ณ„์‚ฐ์ด ํ•„์š” ์—†๋Š” ์กฐ๊ฑด์€ filter context๋ฅผ ์‚ฌ์šฉํ•ด. ์บ์‹ฑ๋˜์–ด ์„ฑ๋Šฅ์ด ํ›จ์”ฌ ์ข‹์•„:

Filter Context ์‚ฌ์šฉ
GET /blog_posts/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "content": "elasticsearch"
          }
        }
      ],
      "filter": [
        {
          "term": {
            "author": "๊น€๊ฐœ๋ฐœ"
          }
        },
        {
          "range": {
            "published_date": {
              "gte": "2024-01-01"
            }
          }
        }
      ]
    }
  }
}

2. ํ•„์š”ํ•œ ํ•„๋“œ๋งŒ ๊ฐ€์ ธ์˜ค๊ธฐ

_source filtering์„ ์‚ฌ์šฉํ•ด์„œ ํ•„์š”ํ•œ ํ•„๋“œ๋งŒ ๋ฐ˜ํ™˜๋ฐ›์•„:

ํ•„๋“œ ํ•„ํ„ฐ๋ง
GET /blog_posts/_search
{
  "_source": ["title", "author", "published_date"],
  "query": {
    "match_all": {}
  }
}

3. ํŽ˜์ด์ง€๋„ค์ด์…˜ ์ตœ์ ํ™”

๊นŠ์€ ํŽ˜์ด์ง€๋„ค์ด์…˜์€ ์„ฑ๋Šฅ์ด ๋‚˜๋น . Search After๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒŒ ์ข‹์•„:

Search After ์‚ฌ์šฉ
GET /blog_posts/_search
{
  "size": 10,
  "query": {
    "match_all": {}
  },
  "sort": [
    {"published_date": "desc"},
    {"_id": "asc"}
  ],
  "search_after": ["2024-01-15", "abc123"]
}

๐Ÿ›ก๏ธ ๋ณด์•ˆ ์„ค์ •ํ•˜๊ธฐ

์šด์˜ ํ™˜๊ฒฝ์—์„œ๋Š” ๋ณด์•ˆ์ด ์ •๋ง ์ค‘์š”ํ•ด! Elasticsearch 8.x๋ถ€ํ„ฐ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ณด์•ˆ์ด ํ™œ์„ฑํ™”๋˜์–ด ์žˆ์ง€๋งŒ, ์ œ๋Œ€๋กœ ์„ค์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„์•ผ ํ•ด. ๐Ÿ”’

๐Ÿ” ์‚ฌ์šฉ์ž ์ธ์ฆ ์„ค์ •

Elasticsearch๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ elastic์ด๋ผ๋Š” ์Šˆํผ์œ ์ € ๊ณ„์ •์„ ์ œ๊ณตํ•ด. ์ถ”๊ฐ€ ์‚ฌ์šฉ์ž๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž:

์‚ฌ์šฉ์ž ์ƒ์„ฑ
POST /_security/user/developer
{
  "password" : "dev_password_123!",
  "roles" : [ "developer_role" ],
  "full_name" : "๊ฐœ๋ฐœ์ž",
  "email" : "dev@example.com"
}

๐Ÿ‘ฅ ์—ญํ•  ๊ธฐ๋ฐ˜ ์ ‘๊ทผ ์ œ์–ด

์—ญํ• (Role)์„ ๋งŒ๋“ค์–ด์„œ ์„ธ๋ฐ€ํ•œ ๊ถŒํ•œ ๊ด€๋ฆฌ๋ฅผ ํ•  ์ˆ˜ ์žˆ์–ด:

์—ญํ•  ์ƒ์„ฑ
POST /_security/role/developer_role
{
  "cluster": ["monitor"],
  "indices": [
    {
      "names": ["blog_posts", "korean_blog"],
      "privileges": ["read", "write", "create_index"]
    }
  ]
}

๐Ÿ”‘ ์ฃผ์š” ๊ถŒํ•œ ์ข…๋ฅ˜

ํด๋Ÿฌ์Šคํ„ฐ ๊ถŒํ•œ:
โ€ข all: ๋ชจ๋“  ํด๋Ÿฌ์Šคํ„ฐ ์ž‘์—…
โ€ข monitor: ํด๋Ÿฌ์Šคํ„ฐ ์ƒํƒœ ์กฐํšŒ
โ€ข manage: ํด๋Ÿฌ์Šคํ„ฐ ์„ค์ • ๋ณ€๊ฒฝ

์ธ๋ฑ์Šค ๊ถŒํ•œ:
โ€ข read: ๋ฌธ์„œ ์กฐํšŒ ๋ฐ ๊ฒ€์ƒ‰
โ€ข write: ๋ฌธ์„œ ์ƒ์„ฑ, ์ˆ˜์ •, ์‚ญ์ œ
โ€ข create_index: ์ธ๋ฑ์Šค ์ƒ์„ฑ
โ€ข delete_index: ์ธ๋ฑ์Šค ์‚ญ์ œ
โ€ข manage: ์ธ๋ฑ์Šค ์„ค์ • ๋ณ€๊ฒฝ

๐ŸŒ ๋„คํŠธ์›Œํฌ ๋ณด์•ˆ

elasticsearch.yml ํŒŒ์ผ์—์„œ ๋„คํŠธ์›Œํฌ ์„ค์ •์„ ์กฐ์ •ํ•ด:

elasticsearch.yml
# ํŠน์ • IP๋งŒ ์ ‘๊ทผ ํ—ˆ์šฉ
network.host: 192.168.1.100

# HTTPS ํ™œ์„ฑํ™”
xpack.security.http.ssl.enabled: true
xpack.security.http.ssl.keystore.path: certs/http.p12

# ๋…ธ๋“œ ๊ฐ„ ํ†ต์‹  ์•”ํ˜ธํ™”
xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.keystore.path: certs/transport.p12

โš ๏ธ ๋ณด์•ˆ ์ฒดํฌ๋ฆฌ์ŠคํŠธ
โœ“ ๊ธฐ๋ณธ ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝํ•˜๊ธฐ
โœ“ ๋ถˆํ•„์š”ํ•œ ํ”Œ๋Ÿฌ๊ทธ์ธ ์ œ๊ฑฐํ•˜๊ธฐ
โœ“ ๋ฐฉํ™”๋ฒฝ ์„ค์ •ํ•˜๊ธฐ
โœ“ ์ •๊ธฐ์ ์ธ ๋ณด์•ˆ ์—…๋ฐ์ดํŠธ
โœ“ ๊ฐ์‚ฌ ๋กœ๊ทธ ํ™œ์„ฑํ™”ํ•˜๊ธฐ
โœ“ ๋ฐฑ์—… ์ •์ฑ… ์ˆ˜๋ฆฝํ•˜๊ธฐ

๐Ÿ”ง ๋ชจ๋‹ˆํ„ฐ๋ง๊ณผ ์œ ์ง€๋ณด์ˆ˜

Elasticsearch๋ฅผ ์•ˆ์ •์ ์œผ๋กœ ์šด์˜ํ•˜๋ ค๋ฉด ์ง€์†์ ์ธ ๋ชจ๋‹ˆํ„ฐ๋ง์ด ํ•„์ˆ˜์•ผ! ์–ด๋–ค ์ง€ํ‘œ๋“ค์„ ๋ด์•ผ ํ•˜๋Š”์ง€ ์•Œ์•„๋ณด์ž. ๐Ÿ“Š

๐Ÿ“ˆ ํด๋Ÿฌ์Šคํ„ฐ ์ƒํƒœ ํ™•์ธ

ํด๋Ÿฌ์Šคํ„ฐ ํ—ฌ์Šค ์ฒดํฌ
GET /_cluster/health

ํด๋Ÿฌ์Šคํ„ฐ ์ƒํƒœ๋Š” ์„ธ ๊ฐ€์ง€ ์ƒ‰์œผ๋กœ ํ‘œ์‹œ๋ผ:

๐ŸŸข Green: ๋ชจ๋“  ์ƒค๋“œ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ํ• ๋‹น๋จ (์ตœ์ƒ์˜ ์ƒํƒœ)
๐ŸŸก Yellow: ๋ชจ๋“  Primary ์ƒค๋“œ๋Š” ํ• ๋‹น๋˜์—ˆ์ง€๋งŒ ์ผ๋ถ€ Replica ์ƒค๋“œ๊ฐ€ ํ• ๋‹น๋˜์ง€ ์•Š์Œ
๐Ÿ”ด Red: ์ผ๋ถ€ Primary ์ƒค๋“œ๊ฐ€ ํ• ๋‹น๋˜์ง€ ์•Š์Œ (๋ฐ์ดํ„ฐ ์†์‹ค ๊ฐ€๋Šฅ์„ฑ)

๐Ÿ’พ ๋…ธ๋“œ ํ†ต๊ณ„ ํ™•์ธ

๋…ธ๋“œ ์ƒํƒœ ์กฐํšŒ
GET /_nodes/stats

์ด API๋Š” ๊ฐ ๋…ธ๋“œ์˜ CPU, ๋ฉ”๋ชจ๋ฆฌ, ๋””์Šคํฌ, JVM ์ƒํƒœ ๋“ฑ ์ƒ์„ธํ•œ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•ด. ์ •๊ธฐ์ ์œผ๋กœ ํ™•์ธํ•ด์„œ ๋ฆฌ์†Œ์Šค ๋ถ€์กฑ ์ƒํ™ฉ์„ ๋ฏธ๋ฆฌ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ์–ด! ๐ŸŽฏ

๐Ÿ” ์ธ๋ฑ์Šค ํ†ต๊ณ„

์ธ๋ฑ์Šค ์ƒํƒœ ์กฐํšŒ
GET /blog_posts/_stats

์ธ๋ฑ์Šค๋ณ„ ๋ฌธ์„œ ๊ฐœ์ˆ˜, ์ €์žฅ ์šฉ๋Ÿ‰, ๊ฒ€์ƒ‰ ํšŸ์ˆ˜, ์ƒ‰์ธ ์†๋„ ๋“ฑ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์–ด. ์–ด๋–ค ์ธ๋ฑ์Šค๊ฐ€ ๋ฆฌ์†Œ์Šค๋ฅผ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š”์ง€ ํŒŒ์•…ํ•˜๋Š” ๋ฐ ์œ ์šฉํ•ด!

๐Ÿšจ ๋А๋ฆฐ ์ฟผ๋ฆฌ ๋กœ๊น…

์„ฑ๋Šฅ ๋ฌธ์ œ๋ฅผ ์ฐพ๊ธฐ ์œ„ํ•ด ๋А๋ฆฐ ์ฟผ๋ฆฌ๋ฅผ ๋กœ๊น…ํ•  ์ˆ˜ ์žˆ์–ด:

Slow Log ์„ค์ •
PUT /blog_posts/_settings
{
  "index.search.slowlog.threshold.query.warn": "10s",
  "index.search.slowlog.threshold.query.info": "5s",
  "index.search.slowlog.threshold.query.debug": "2s",
  "index.search.slowlog.threshold.fetch.warn": "1s",
  "index.indexing.slowlog.threshold.index.warn": "10s"
}

์ด๋ ‡๊ฒŒ ์„ค์ •ํ•˜๋ฉด ์ง€์ •ํ•œ ์‹œ๊ฐ„๋ณด๋‹ค ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๋Š” ์ฟผ๋ฆฌ๊ฐ€ ๋กœ๊ทธ์— ๊ธฐ๋ก๋ผ. ์„ฑ๋Šฅ ๋ณ‘๋ชฉ ์ง€์ ์„ ์ฐพ๋Š” ๋ฐ ์ •๋ง ์œ ์šฉํ•ด! ๐Ÿ”

๐Ÿ”„ ์ธ๋ฑ์Šค ๋ผ์ดํ”„์‚ฌ์ดํด ๊ด€๋ฆฌ

์‹œ๊ฐ„์ด ์ง€๋‚˜๋ฉด์„œ ์Œ“์ด๋Š” ๋กœ๊ทธ ๋ฐ์ดํ„ฐ ๊ฐ™์€ ๊ฒฝ์šฐ, ์ž๋™์œผ๋กœ ๊ด€๋ฆฌํ•˜๋Š” ์ •์ฑ…์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด:

ILM ์ •์ฑ… ์ƒ์„ฑ
PUT /_ilm/policy/logs_policy
{
  "policy": {
    "phases": {
      "hot": {
        "actions": {
          "rollover": {
            "max_size": "50GB",
            "max_age": "7d"
          }
        }
      },
      "warm": {
        "min_age": "7d",
        "actions": {
          "shrink": {
            "number_of_shards": 1
          },
          "forcemerge": {
            "max_num_segments": 1
          }
        }
      },
      "cold": {
        "min_age": "30d",
        "actions": {
          "freeze": {}
        }
      },
      "delete": {
        "min_age": "90d",
        "actions": {
          "delete": {}
        }
      }
    }
  }
}

์ด ์ •์ฑ…์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ž๋™์œผ๋กœ ๊ด€๋ฆฌํ•ด์ค˜:
โ€ข Hot: ์ตœ์‹  ๋ฐ์ดํ„ฐ, ํ™œ๋ฐœํ•˜๊ฒŒ ๊ฒ€์ƒ‰๋จ
โ€ข Warm: ์กฐ๊ธˆ ์˜ค๋ž˜๋œ ๋ฐ์ดํ„ฐ, ๊ฒ€์ƒ‰ ๋นˆ๋„ ๋‚ฎ์Œ
โ€ข Cold: ๊ฑฐ์˜ ๊ฒ€์ƒ‰ ์•ˆ ๋˜๋Š” ๋ฐ์ดํ„ฐ
โ€ข Delete: ๋ณด๊ด€ ๊ธฐ๊ฐ„ ์ง€๋‚œ ๋ฐ์ดํ„ฐ ์ž๋™ ์‚ญ์ œ

์‹ค์‹œ๊ฐ„ ๋ชจ๋‹ˆํ„ฐ๋ง ๋Œ€์‹œ๋ณด๋“œ ํด๋Ÿฌ์Šคํ„ฐ ์ƒํƒœ โœ“ GREEN - ์ •์ƒ ์ž‘๋™ CPU ์‚ฌ์šฉ๋ฅ  70% ํ‰๊ท  ๋ถ€ํ•˜ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰ 85% 16GB / 19GB ๊ฒ€์ƒ‰ ์„ฑ๋Šฅ 0.023s ํ‰๊ท  ์‘๋‹ต ์‹œ๊ฐ„ โ†‘ 15% ๊ฐœ์„  ์ƒ‰์ธ ์†๋„ 12.5K ๋ฌธ์„œ/์ดˆ ์•ˆ์ •์  ์ด ๋ฌธ์„œ ์ˆ˜ 2.4M ์ธ๋ฑ์Šค ํฌ๊ธฐ: 48GB โ†‘ 2.3K ์ฆ๊ฐ€

๐Ÿš€ ์‹ค์ „ ํ™œ์šฉ ์‚ฌ๋ก€

์ด๋ก ์€ ์ถฉ๋ถ„ํžˆ ๋ฐฐ์› ์œผ๋‹ˆ, ์ด์ œ ์‹ค์ œ๋กœ ์–ด๋–ป๊ฒŒ ํ™œ์šฉ๋˜๋Š”์ง€ ๊ตฌ์ฒด์ ์ธ ์‚ฌ๋ก€๋ฅผ ์‚ดํŽด๋ณด์ž! ๐Ÿ’ผ

๐Ÿ›’ ์ „์ž์ƒ๊ฑฐ๋ž˜ ์ƒํ’ˆ ๊ฒ€์ƒ‰

์˜จ๋ผ์ธ ์‡ผํ•‘๋ชฐ์—์„œ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๊ฒŒ ๋ญ˜๊นŒ? ๋ฐ”๋กœ ์ƒํ’ˆ ๊ฒ€์ƒ‰์ด์•ผ! ์‚ฌ์šฉ์ž๊ฐ€ ์›ํ•˜๋Š” ์ƒํ’ˆ์„ ๋น ๋ฅด๊ณ  ์ •ํ™•ํ•˜๊ฒŒ ์ฐพ์„ ์ˆ˜ ์žˆ์–ด์•ผ ํ•ด.

์ƒํ’ˆ ์ธ๋ฑ์Šค ์„ค๊ณ„
PUT /products
{
  "settings": {
    "number_of_shards": 5,
    "number_of_replicas": 2,
    "analysis": {
      "analyzer": {
        "product_analyzer": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": ["lowercase", "synonym", "stop"]
        }
      },
      "filter": {
        "synonym": {
          "type": "synonym",
          "synonyms": [
            "๋…ธํŠธ๋ถ, ๋žฉํƒ‘, laptop",
            "์Šค๋งˆํŠธํฐ, ํœด๋Œ€ํฐ, ํ•ธ๋“œํฐ",
            "ํ‹ฐ์…”์ธ , ๋ฐ˜ํŒ”, ํ‹ฐ"
          ]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "name": {
        "type": "text",
        "analyzer": "product_analyzer",
        "fields": {
          "keyword": {
            "type": "keyword"
          }
        }
      },
      "description": {
        "type": "text",
        "analyzer": "product_analyzer"
      },
      "category": {
        "type": "keyword"
      },
      "brand": {
        "type": "keyword"
      },
      "price": {
        "type": "integer"
      },
      "rating": {
        "type": "float"
      },
      "stock": {
        "type": "integer"
      },
      "tags": {
        "type": "keyword"
      },
      "created_at": {
        "type": "date"
      }
    }
  }
}
๋‹ค์ค‘ ์กฐ๊ฑด ์ƒํ’ˆ ๊ฒ€์ƒ‰
GET /products/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "multi_match": {
            "query": "๋ฌด์„  ์ด์–ดํฐ",
            "fields": ["name^3", "description"],
            "type": "best_fields"
          }
        }
      ],
      "filter": [
        {
          "range": {
            "price": {
              "gte": 50000,
              "lte": 200000
            }
          }
        },
        {
          "range": {
            "rating": {
              "gte": 4.0
            }
          }
        },
        {
          "term": {
            "stock": {
              "value": 0,
              "boost": 0
            }
          }
        }
      ],
      "should": [
        {
          "term": {
            "brand": "์‚ผ์„ฑ"
          }
        }
      ]
    }
  },
  "sort": [
    {
      "_score": "desc"
    },
    {
      "rating": "desc"
    }
  ],
  "aggs": {
    "price_ranges": {
      "range": {
        "field": "price",
        "ranges": [
          {"to": 50000},
          {"from": 50000, "to": 100000},
          {"from": 100000, "to": 200000},
          {"from": 200000}
        ]
      }
    },
    "brands": {
      "terms": {
        "field": "brand",
        "size": 10
      }
    }
  }
}

์ด ์ฟผ๋ฆฌ๋Š” ์ƒํ’ˆ๋ช…๊ณผ ์„ค๋ช…์—์„œ "๋ฌด์„  ์ด์–ดํฐ"์„ ๊ฒ€์ƒ‰ํ•˜๊ณ , ๊ฐ€๊ฒฉ ๋ฒ”์œ„์™€ ํ‰์ ์œผ๋กœ ํ•„ํ„ฐ๋งํ•˜๋ฉฐ, ์žฌ๊ณ ๊ฐ€ ์žˆ๋Š” ์ƒํ’ˆ๋งŒ ๋ณด์—ฌ์ค˜. ๋™์‹œ์— ๊ฐ€๊ฒฉ๋Œ€๋ณ„ ์ƒํ’ˆ ์ˆ˜์™€ ๋ธŒ๋žœ๋“œ๋ณ„ ํ†ต๊ณ„๋„ ์ œ๊ณตํ•ด! ๐ŸŽฏ

๐Ÿ“ฐ ๋‰ด์Šค ๊ธฐ์‚ฌ ๊ฒ€์ƒ‰ ์‹œ์Šคํ…œ

๋‰ด์Šค ์‚ฌ์ดํŠธ์—์„œ๋Š” ์ตœ์‹  ๊ธฐ์‚ฌ๋ฅผ ๋น ๋ฅด๊ฒŒ ๊ฒ€์ƒ‰ํ•˜๊ณ , ๊ด€๋ จ ๊ธฐ์‚ฌ๋ฅผ ์ถ”์ฒœํ•˜๋Š” ๊ธฐ๋Šฅ์ด ์ค‘์š”ํ•ด.

๋‰ด์Šค ๊ธฐ์‚ฌ ๊ฒ€์ƒ‰
GET /news/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "content": {
              "query": "์ธ๊ณต์ง€๋Šฅ ๊ธฐ์ˆ  ๋ฐœ์ „",
              "operator": "and"
            }
          }
        }
      ],
      "filter": [
        {
          "range": {
            "published_date": {
              "gte": "now-7d/d"
            }
          }
        }
      ]
    }
  },
  "highlight": {
    "fields": {
      "content": {
        "pre_tags": ["<strong>"],
        "post_tags": ["</strong>"],
        "fragment_size": 150,
        "number_of_fragments": 3
      }
    }
  },
  "suggest": {
    "text": "์ธ๊ณต์ง€๋Šฅ",
    "simple_phrase": {
      "phrase": {
        "field": "content",
        "size": 3,
        "gram_size": 2,
        "direct_generator": [
          {
            "field": "content",
            "suggest_mode": "always"
          }
        ]
      }
    }
  }
}

highlight ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋ฉด ๊ฒ€์ƒ‰์–ด๊ฐ€ ํฌํ•จ๋œ ๋ถ€๋ถ„์„ ๊ฐ•์กฐํ•ด์„œ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ์–ด. ์‚ฌ์šฉ์ž๊ฐ€ ์–ด๋–ค ๋‚ด์šฉ ๋•Œ๋ฌธ์— ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ์— ๋‚˜์™”๋Š”์ง€ ๋ฐ”๋กœ ์•Œ ์ˆ˜ ์žˆ์ง€! โœจ

๐Ÿ“Š ๋กœ๊ทธ ๋ถ„์„ ์‹œ์Šคํ…œ

์„œ๋ฒ„ ๋กœ๊ทธ๋ฅผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ์ˆ˜์ง‘ํ•˜๊ณ  ๋ถ„์„ํ•˜๋Š” ๊ฑด ์šด์˜์— ํ•„์ˆ˜์ ์ด์•ผ. Elasticsearch๋Š” ELK ์Šคํƒ(Elasticsearch, Logstash, Kibana)์˜ ํ•ต์‹ฌ์ด์ง€!

๋กœ๊ทธ ์ธ๋ฑ์Šค ํ…œํ”Œ๋ฆฟ
PUT /_index_template/logs_template
{
  "index_patterns": ["logs-*"],
  "template": {
    "settings": {
      "number_of_shards": 3,
      "number_of_replicas": 1,
      "index.lifecycle.name": "logs_policy"
    },
    "mappings": {
      "properties": {
        "@timestamp": {
          "type": "date"
        },
        "level": {
          "type": "keyword"
        },
        "message": {
          "type": "text"
        },
        "service": {
          "type": "keyword"
        },
        "host": {
          "type": "keyword"
        },
        "response_time": {
          "type": "integer"
        },
        "status_code": {
          "type": "integer"
        },
        "user_agent": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword"
            }
          }
        }
      }
    }
  }
}
์—๋Ÿฌ ๋กœ๊ทธ ๋ถ„์„
GET /logs-*/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "term": {
            "level": "ERROR"
          }
        },
        {
          "range": {
            "@timestamp": {
              "gte": "now-1h"
            }
          }
        }
      ]
    }
  },
  "aggs": {
    "errors_by_service": {
      "terms": {
        "field": "service",
        "size": 10
      },
      "aggs": {
        "error_rate": {
          "date_histogram": {
            "field": "@timestamp",
            "fixed_interval": "5m"
          }
        }
      }
    },
    "slow_requests": {
      "filter": {
        "range": {
          "response_time": {
            "gte": 1000
          }
        }
      },
      "aggs": {
        "avg_response_time": {
          "avg": {
            "field": "response_time"
          }
        }
      }
    }
  }
}

์ด ์ฟผ๋ฆฌ๋Š” ์ตœ๊ทผ 1์‹œ๊ฐ„ ๋™์•ˆ์˜ ์—๋Ÿฌ ๋กœ๊ทธ๋ฅผ ๋ถ„์„ํ•ด์„œ ์„œ๋น„์Šค๋ณ„ ์—๋Ÿฌ ๋ฐœ์ƒ ์ถ”์ด์™€ ๋А๋ฆฐ ์š”์ฒญ์˜ ํ‰๊ท  ์‘๋‹ต ์‹œ๊ฐ„์„ ๋ณด์—ฌ์ค˜. ๋ฌธ์ œ๋ฅผ ๋น ๋ฅด๊ฒŒ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ์–ด! ๐Ÿ”

๐Ÿ’ผ ์žฌ๋Šฅ๋„ท์—์„œ ์‹ค์ „ ๊ฒฝํ—˜ ์Œ“๊ธฐ
์ด๋ก ์„ ๋ฐฐ์› ๋‹ค๋ฉด ์ด์ œ ์‹ค์ „์ด์•ผ! ์žฌ๋Šฅ๋„ท(https://www.jaenung.net)์—์„œ๋Š” ์‹ค์ œ ํ”„๋กœ์ ํŠธ ๊ฒฝํ—˜์ด ์žˆ๋Š” ์ „๋ฌธ๊ฐ€๋“ค๊ณผ ํ•จ๊ป˜ Elasticsearch๋ฅผ ํ™œ์šฉํ•œ ์‹ค๋ฌด ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ์–ด. ํฌํŠธํด๋ฆฌ์˜ค๋„ ๋งŒ๋“ค๊ณ  ์‹ค๋ ฅ๋„ ํ‚ค์šธ ์ˆ˜ ์žˆ๋Š” ์ข‹์€ ๊ธฐํšŒ์ง€! ๐Ÿš€

๐ŸŽ“ ๋” ๋‚˜์•„๊ฐ€๊ธฐ

์—ฌ๊ธฐ๊นŒ์ง€ ์™”๋‹ค๋ฉด Elasticsearch์˜ ๊ธฐ๋ณธ์€ ๋งˆ์Šคํ„ฐํ•œ ๊ฑฐ์•ผ! ํ•˜์ง€๋งŒ ๋ฐฐ์šธ ๊ฒŒ ๋” ๋งŽ์•„. ๋” ๊นŠ์ด ์žˆ๋Š” ์ฃผ์ œ๋“ค์„ ์†Œ๊ฐœํ•ด์ค„๊ฒŒ. ๐Ÿ“š

๐Ÿง  ๋จธ์‹ ๋Ÿฌ๋‹ ๊ธฐ๋Šฅ

Elasticsearch๋Š” X-Pack์„ ํ†ตํ•ด ๋จธ์‹ ๋Ÿฌ๋‹ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ด. ์ด์ƒ ํƒ์ง€(Anomaly Detection), ์˜ˆ์ธก(Forecasting) ๋“ฑ์„ ์ž๋™์œผ๋กœ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์–ด:

๐Ÿค– ML ํ™œ์šฉ ์‚ฌ๋ก€

โ€ข ๋น„์ •์ƒ์ ์ธ ํŠธ๋ž˜ํ”ฝ ํŒจํ„ด ๊ฐ์ง€
โ€ข ์„œ๋ฒ„ ๋ฆฌ์†Œ์Šค ์‚ฌ์šฉ๋Ÿ‰ ์˜ˆ์ธก
โ€ข ์‚ฌ์šฉ์ž ํ–‰๋™ ํŒจํ„ด ๋ถ„์„
โ€ข ๋ณด์•ˆ ์œ„ํ˜‘ ํƒ์ง€
โ€ข ๋น„์ฆˆ๋‹ˆ์Šค ์ง€ํ‘œ ์ด์ƒ ๊ฐ์ง€

๐Ÿ”„ Cross-Cluster Search

์—ฌ๋Ÿฌ Elasticsearch ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ์—ฐ๊ฒฐํ•ด์„œ ๋™์‹œ์— ๊ฒ€์ƒ‰ํ•  ์ˆ˜ ์žˆ์–ด. ์ง€์—ญ๋ณ„๋กœ ๋ถ„์‚ฐ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ํ•œ ๋ฒˆ์— ๊ฒ€์ƒ‰ํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์œ ์šฉํ•ด!

๐Ÿ“Š Kibana ํ™œ์šฉ

Kibana๋Š” Elasticsearch์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์‹œ๊ฐํ™”ํ•˜๋Š” ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ์•ผ. ๋Œ€์‹œ๋ณด๋“œ๋ฅผ ๋งŒ๋“ค์–ด์„œ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•  ์ˆ˜ ์žˆ์–ด:

Kibana ์ฃผ์š” ๊ธฐ๋Šฅ

โ€ข Discover: ๋ฐ์ดํ„ฐ ํƒ์ƒ‰ ๋ฐ ๊ฒ€์ƒ‰
โ€ข Visualize: ์ฐจํŠธ, ๊ทธ๋ž˜ํ”„ ๋“ฑ ์‹œ๊ฐํ™” ์ƒ์„ฑ
โ€ข Dashboard: ์—ฌ๋Ÿฌ ์‹œ๊ฐํ™”๋ฅผ ์กฐํ•ฉํ•œ ๋Œ€์‹œ๋ณด๋“œ
โ€ข Canvas: ํ”„๋ ˆ์  ํ…Œ์ด์…˜์šฉ ์ธํฌ๊ทธ๋ž˜ํ”ฝ
โ€ข Maps: ์ง€๋ฆฌ ๋ฐ์ดํ„ฐ ์‹œ๊ฐํ™”
โ€ข Machine Learning: ML ์ž‘์—… ๊ด€๋ฆฌ

๐Ÿ”Œ Logstash์™€ Beats

๋ฐ์ดํ„ฐ๋ฅผ Elasticsearch๋กœ ์ˆ˜์ง‘ํ•˜๋Š” ๋„๊ตฌ๋“ค์ด์•ผ:

๐Ÿ“ฅ ๋ฐ์ดํ„ฐ ์ˆ˜์ง‘ ๋„๊ตฌ

Logstash: ๋‹ค์–‘ํ•œ ์†Œ์Šค์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ง‘, ๋ณ€ํ™˜, ์ „์†กํ•˜๋Š” ํŒŒ์ดํ”„๋ผ์ธ
Filebeat: ๋กœ๊ทธ ํŒŒ์ผ ์ˆ˜์ง‘
Metricbeat: ์‹œ์Šคํ…œ ๋ฐ ์„œ๋น„์Šค ๋ฉ”ํŠธ๋ฆญ ์ˆ˜์ง‘
Packetbeat: ๋„คํŠธ์›Œํฌ ํŒจํ‚ท ๋ถ„์„
Heartbeat: ์„œ๋น„์Šค ๊ฐ€์šฉ์„ฑ ๋ชจ๋‹ˆํ„ฐ๋ง
Auditbeat: ๋ณด์•ˆ ๊ฐ์‚ฌ ๋ฐ์ดํ„ฐ ์ˆ˜์ง‘

๐ŸŒ Elasticsearch Service (Cloud)

์ง์ ‘ ์ธํ”„๋ผ๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ๋ถ€๋‹ด์Šค๋Ÿฝ๋‹ค๋ฉด Elastic Cloud๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด. AWS, GCP, Azure์—์„œ ๊ด€๋ฆฌํ˜• ์„œ๋น„์Šค๋กœ ์ œ๊ณต๋ผ:

ํด๋ผ์šฐ๋“œ ์„œ๋น„์Šค์˜ ์žฅ์ 

โœ“ ์ž๋™ ๋ฐฑ์—… ๋ฐ ๋ณต๊ตฌ
โœ“ ์ž๋™ ์—…๊ทธ๋ ˆ์ด๋“œ
โœ“ ๋ณด์•ˆ ํŒจ์น˜ ์ž๋™ ์ ์šฉ
โœ“ ์Šค์ผ€์ผ๋ง ๊ฐ„ํŽธ
โœ“ 24/7 ๋ชจ๋‹ˆํ„ฐ๋ง
โœ“ ์ „๋ฌธ๊ฐ€ ์ง€์›

๐Ÿ’ก ์‹ค๋ฌด ํŒ๊ณผ ๋ฒ ์ŠคํŠธ ํ”„๋ž™ํ‹ฐ์Šค

๋งˆ์ง€๋ง‰์œผ๋กœ ์‹ค๋ฌด์—์„œ ์ •๋ง ์œ ์šฉํ•œ ํŒ๋“ค์„ ๊ณต์œ ํ• ๊ฒŒ! ์ด๊ฑด ๊ฒฝํ—˜์—์„œ ๋‚˜์˜จ ๋…ธํ•˜์šฐ๋“ค์ด์•ผ. ๐ŸŽฏ

1. ์ธ๋ฑ์Šค ๋„ค์ด๋ฐ ๊ทœ์น™

์ธ๋ฑ์Šค ์ด๋ฆ„์€ ์ผ๊ด€์„ฑ ์žˆ๊ฒŒ ์ง€์–ด์•ผ ํ•ด. ์ถ”์ฒœํ•˜๋Š” ํŒจํ„ด์€:
{์„œ๋น„์Šค๋ช…}-{๋ฐ์ดํ„ฐํƒ€์ž…}-{๋‚ ์งœ}

์˜ˆ: myapp-logs-2024.01.15, myapp-products-v1

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๊ด€๋ฆฌ๊ฐ€ ํ›จ์”ฌ ์‰ฌ์›Œ์ ธ!

2. ๋งคํ•‘์€ ์‹ ์ค‘ํ•˜๊ฒŒ

ํ•œ ๋ฒˆ ์ƒ์„ฑ๋œ ํ•„๋“œ์˜ ํƒ€์ž…์€ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†์–ด. ์ฒ˜์Œ๋ถ€ํ„ฐ ์‹ ์ค‘ํ•˜๊ฒŒ ์„ค๊ณ„ํ•ด์•ผ ํ•ด. ๋ณ€๊ฒฝ์ด ํ•„์š”ํ•˜๋ฉด Reindex API๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š”๋ฐ, ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ ค!

3. ์ ์ ˆํ•œ ์ƒค๋“œ ํฌ๊ธฐ ์œ ์ง€

์ƒค๋“œ๊ฐ€ ๋„ˆ๋ฌด ํฌ๋ฉด ๋ณต๊ตฌ ์‹œ๊ฐ„์ด ๊ธธ์–ด์ง€๊ณ , ๋„ˆ๋ฌด ์ž‘์œผ๋ฉด ์˜ค๋ฒ„ํ—ค๋“œ๊ฐ€ ๋ฐœ์ƒํ•ด. 20GB~50GB ์‚ฌ์ด๋ฅผ ์œ ์ง€ํ•˜๋Š” ๊ฒŒ ์ข‹์•„. ์‹œ๊ณ„์—ด ๋ฐ์ดํ„ฐ๋Š” ๋‚ ์งœ๋ณ„๋กœ ์ธ๋ฑ์Šค๋ฅผ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒŒ ํšจ๊ณผ์ ์ด์•ผ!

4. ๋ณต์ œ๋ณธ ํ™œ์šฉ

๋ณต์ œ๋ณธ(Replica)์€ ๋‹จ์ˆœํžˆ ๋ฐฑ์—…์ด ์•„๋‹ˆ์•ผ. ๊ฒ€์ƒ‰ ์„ฑ๋Šฅ๋„ ํ–ฅ์ƒ์‹œ์ผœ์ค˜. ๊ฒ€์ƒ‰ ์š”์ฒญ์ด ๋งŽ๋‹ค๋ฉด ๋ณต์ œ๋ณธ ๊ฐœ์ˆ˜๋ฅผ ๋Š˜๋ฆฌ๋Š” ๊ฒƒ๋„ ์ข‹์€ ์ „๋žต์ด์•ผ!

5. ์ •๊ธฐ์ ์ธ ๋ฐฑ์—…

Snapshot API๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ •๊ธฐ์ ์œผ๋กœ ๋ฐฑ์—…ํ•ด์•ผ ํ•ด. ์žฌ๋‚œ ๋ณต๊ตฌ ๊ณ„ํš์€ ํ•„์ˆ˜์•ผ!

์Šค๋ƒ…์ƒท ์ƒ์„ฑ
PUT /_snapshot/my_backup
{
  "type": "fs",
  "settings": {
    "location": "/mount/backups/my_backup"
  }
}

POST /_snapshot/my_backup/snapshot_1?wait_for_completion=true

6. ๋ฌธ์„œ ID ์ „๋žต

์ž๋™ ์ƒ์„ฑ ID๋Š” ํŽธํ•˜์ง€๋งŒ, ์˜๋ฏธ ์žˆ๋Š” ID๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ค‘๋ณต ์ฒดํฌ๋‚˜ ์—…๋ฐ์ดํŠธ๊ฐ€ ์‰ฌ์›Œ์ ธ. ์ƒํ™ฉ์— ๋งž๊ฒŒ ์„ ํƒํ•ด!

7. ์บ์‹ฑ ํ™œ์šฉ

์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” ์ฟผ๋ฆฌ๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ ˆ๋ฒจ์—์„œ ์บ์‹ฑํ•˜๋Š” ๊ฒŒ ์ข‹์•„. Redis๋‚˜ Memcached๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋ฉด ์„ฑ๋Šฅ์ด ํฌ๊ฒŒ ํ–ฅ์ƒ๋ผ!

8. ๋ชจ๋‹ˆํ„ฐ๋ง ์ž๋™ํ™”

Elasticsearch์˜ ์ƒํƒœ๋ฅผ ์ž๋™์œผ๋กœ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๊ณ , ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์•Œ๋ฆผ์„ ๋ฐ›๋„๋ก ์„ค์ •ํ•ด. Kibana์˜ Watcher๋‚˜ ์™ธ๋ถ€ ๋ชจ๋‹ˆํ„ฐ๋ง ๋„๊ตฌ๋ฅผ ํ™œ์šฉํ•ด!

โš ๏ธ ํ”ํ•œ ์‹ค์ˆ˜๋“ค
โŒ ํ”„๋กœ๋•์…˜์—์„œ wildcard ์ฟผ๋ฆฌ ๋‚จ์šฉ
โŒ ๋„ˆ๋ฌด ๋งŽ์€ ํ•„๋“œ ์ •์˜ (1000๊ฐœ ์ด์ƒ)
โŒ ๊นŠ์€ ํŽ˜์ด์ง€๋„ค์ด์…˜ (from + size > 10000)
โŒ ๋ณด์•ˆ ์„ค์ • ์—†์ด ์šด์˜
โŒ ๋ฐฑ์—… ์—†์ด ์šด์˜
โŒ ๋กœ๊ทธ ๋ ˆ๋ฒจ์„ DEBUG๋กœ ์šด์˜

๐ŸŽฌ ๋งˆ๋ฌด๋ฆฌํ•˜๋ฉฐ

์™€! ์—ฌ๊ธฐ๊นŒ์ง€ ์ •๋ง ๊ธด ์—ฌ์ •์ด์—ˆ์–ด! ๐ŸŽ‰ Elasticsearch์˜ ๊ธฐ๋ณธ ๊ฐœ๋…๋ถ€ํ„ฐ ์‹ค์ „ ํ™œ์šฉ๊นŒ์ง€ ํ•จ๊ป˜ ์‚ดํŽด๋ดค์–ด. ์ฒ˜์Œ์—๋Š” ๋ณต์žกํ•ด ๋ณด์˜€์„ ์ˆ˜๋„ ์žˆ์ง€๋งŒ, ํ•˜๋‚˜์”ฉ ๋”ฐ๋ผํ•˜๋‹ค ๋ณด๋ฉด ์ƒ๊ฐ๋ณด๋‹ค ์–ด๋ ต์ง€ ์•Š๋‹ค๋Š” ๊ฑธ ์•Œ๊ฒŒ ๋  ๊ฑฐ์•ผ.

Elasticsearch๋Š” ์ •๋ง ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ์•ผ. ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋กœ๊ทธ ๋ถ„์„, ์‹ค์‹œ๊ฐ„ ๋ชจ๋‹ˆํ„ฐ๋ง, ๋น„์ฆˆ๋‹ˆ์Šค ์ธํ…”๋ฆฌ์ „์Šค ๋“ฑ ๋‹ค์–‘ํ•œ ๋ถ„์•ผ์—์„œ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์–ด. ํŠนํžˆ ๋น…๋ฐ์ดํ„ฐ ์‹œ๋Œ€์— ํ•„์ˆ˜์ ์ธ ๊ธฐ์ˆ ์ด์ง€! ๐Ÿ“Š

๊ธฐ์–ตํ•ด์•ผ ํ•  ํ•ต์‹ฌ ํฌ์ธํŠธ๋“ค์„ ์ •๋ฆฌํ•ด๋ณผ๊ฒŒ:

๐ŸŽฏ ํ•ต์‹ฌ ์š”์•ฝ

1. ๊ตฌ์กฐ ์ดํ•ด: Cluster โ†’ Node โ†’ Index โ†’ Document โ†’ Shard
2. ๊ฒ€์ƒ‰ ๋งˆ์Šคํ„ฐ: Match, Bool, Term, Range ์ฟผ๋ฆฌ ํ™œ์šฉ
3. ์„ฑ๋Šฅ ์ตœ์ ํ™”: ์ ์ ˆํ•œ ์ƒค๋“œ ํฌ๊ธฐ, Filter Context, ์บ์‹ฑ
4. ํ•œ๊ธ€ ๊ฒ€์ƒ‰: Nori ๋ถ„์„๊ธฐ๋กœ ํ˜•ํƒœ์†Œ ๋ถ„์„
5. ๋ณด์•ˆ: ์ธ์ฆ, ๊ถŒํ•œ ๊ด€๋ฆฌ, ๋„คํŠธ์›Œํฌ ๋ณด์•ˆ
6. ๋ชจ๋‹ˆํ„ฐ๋ง: ํด๋Ÿฌ์Šคํ„ฐ ์ƒํƒœ, ์„ฑ๋Šฅ ์ง€ํ‘œ ์ง€์† ํ™•์ธ
7. ์‹ค์ „ ํ™œ์šฉ: ์ „์ž์ƒ๊ฑฐ๋ž˜, ๋กœ๊ทธ ๋ถ„์„, ๋‰ด์Šค ๊ฒ€์ƒ‰ ๋“ฑ
8. ๋ฒ ์ŠคํŠธ ํ”„๋ž™ํ‹ฐ์Šค: ๋„ค์ด๋ฐ ๊ทœ์น™, ๋ฐฑ์—…, ์ ์ ˆํ•œ ์„ค๊ณ„

Elasticsearch๋Š” ๊ณ„์† ๋ฐœ์ „ํ•˜๊ณ  ์žˆ์–ด. ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ๋“ค์ด ๊ณ„์† ์ถ”๊ฐ€๋˜๊ณ , ์„ฑ๋Šฅ๋„ ๊ฐœ์„ ๋˜๊ณ  ์žˆ์ง€. ๊ณต์‹ ๋ฌธ์„œ๋ฅผ ์ž์ฃผ ํ™•์ธํ•˜๊ณ , ์ปค๋ฎค๋‹ˆํ‹ฐ์— ์ฐธ์—ฌํ•˜๋ฉด์„œ ์ตœ์‹  ํŠธ๋ Œ๋“œ๋ฅผ ๋”ฐ๋ผ๊ฐ€๋Š” ๊ฒŒ ์ค‘์š”ํ•ด! ๐Ÿš€

์ฒ˜์Œ์—๋Š” ์ž‘์€ ํ”„๋กœ์ ํŠธ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด๋ด. ๊ฐ„๋‹จํ•œ ๋ธ”๋กœ๊ทธ ๊ฒ€์ƒ‰์ด๋‚˜ ์ƒํ’ˆ ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ์„ ๋งŒ๋“ค์–ด๋ณด๋ฉด์„œ ๊ฐ์„ ์ตํžˆ๋Š” ๊ฑฐ์•ผ. ๊ทธ๋Ÿฌ๋‹ค ๋ณด๋ฉด ์ ์  ๋ณต์žกํ•œ ์‹œ์Šคํ…œ๋„ ๊ตฌ์ถ•ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋  ๊ฑฐ์•ผ! ๐Ÿ’ช

ํ˜น์‹œ ๋ง‰ํžˆ๋Š” ๋ถ€๋ถ„์ด ์žˆ๊ฑฐ๋‚˜ ๋” ๊นŠ์ด ์žˆ๋Š” ํ•™์Šต์ด ํ•„์š”ํ•˜๋‹ค๋ฉด, ์žฌ๋Šฅ๋„ท ๊ฐ™์€ ํ”Œ๋žซํผ์—์„œ ์ „๋ฌธ๊ฐ€์˜ ๋„์›€์„ ๋ฐ›๋Š” ๊ฒƒ๋„ ์ข‹์€ ๋ฐฉ๋ฒ•์ด์•ผ. ํ˜ผ์ž ๊ณ ๋ฏผํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ๊ฒฝํ—˜ ๋งŽ์€ ์‚ฌ๋žŒ์˜ ์กฐ์–ธ์„ ๋“ฃ๋Š” ๊ฒŒ ํ›จ์”ฌ ๋น ๋ฅด๊ฒŒ ์„ฑ์žฅํ•  ์ˆ˜ ์žˆ๊ฑฐ๋“ ! ๐ŸŽ“

์ž, ์ด์ œ ๋‹น์‹  ์ฐจ๋ก€์•ผ! Elasticsearch๋ฅผ ์„ค์น˜ํ•˜๊ณ , ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ๊ณ , ๊ฒ€์ƒ‰ํ•ด๋ณด๋ฉด์„œ ์ง์ ‘ ๊ฒฝํ—˜ํ•ด๋ด. ์ด๋ก ๋งŒ์œผ๋กœ๋Š” ๋ถ€์กฑํ•ด. ์‹ค์ œ๋กœ ์†์œผ๋กœ ์ฝ”๋”ฉํ•˜๊ณ , ์—๋Ÿฌ๋ฅผ ๋งŒ๋‚˜๊ณ , ํ•ด๊ฒฐํ•˜๋ฉด์„œ ์ง„์งœ ์‹ค๋ ฅ์ด ๋Š˜์–ด๋‚˜๋Š” ๊ฑฐ์•ผ! ๐Ÿ”ฅ

๊ฒ€์ƒ‰ ์—”์ง„ ๊ตฌ์ถ•์˜ ์„ธ๊ณ„๋Š” ์ •๋ง ํฅ๋ฏธ์ง„์ง„ํ•ด. ์‚ฌ์šฉ์ž๋“ค์ด ์›ํ•˜๋Š” ์ •๋ณด๋ฅผ ๋น ๋ฅด๊ณ  ์ •ํ™•ํ•˜๊ฒŒ ์ฐพ์•„์ฃผ๋Š” ์‹œ์Šคํ…œ์„ ๋งŒ๋“œ๋Š” ๊ฑด ์ •๋ง ๋ณด๋žŒ์ฐฌ ์ผ์ด์•ผ. ๋‹น์‹ ๋„ ๋ฉ‹์ง„ ๊ฒ€์ƒ‰ ์‹œ์Šคํ…œ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์„ ๊ฑฐ์•ผ! ํ™”์ดํŒ…! ๐Ÿ’ซ

๐Ÿ“š ์ถ”๊ฐ€ ํ•™์Šต ์ž๋ฃŒ
โ€ข Elastic ๊ณต์‹ ๋ฌธ์„œ: https://www.elastic.co/guide
โ€ข Elasticsearch ๊ณต์‹ ๋ธ”๋กœ๊ทธ: https://www.elastic.co/blog
โ€ข Elastic Community: https://discuss.elastic.co
โ€ข GitHub Elasticsearch: https://github.com/elastic/elasticsearch
โ€ข Elastic ์œ ํŠœ๋ธŒ ์ฑ„๋„: ๋‹ค์–‘ํ•œ ํŠœํ† ๋ฆฌ์–ผ๊ณผ ์›จ๋น„๋‚˜

๐ŸŽ‰ ์—ฌ๊ธฐ๊นŒ์ง€ ์ฝ์–ด์ค˜์„œ ์ •๋ง ๊ณ ๋งˆ์›Œ! ๐ŸŽ‰
๋‹น์‹ ์˜ Elasticsearch ์—ฌ์ •์— ํ–‰์šด์„ ๋นŒ์–ด! ๐Ÿš€

๋Œ“๊ธ€ ์ž‘์„ฑ

์ด ๊ธ€์— ๋Œ€ํ•œ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ƒ๊ฐ์„ ๋“ค๋ ค์ฃผ์„ธ์š”

๋Œ“๊ธ€ 0
๋Œ“๊ธ€์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘์ž…๋‹ˆ๋‹ค.

์•„์ง ๋Œ“๊ธ€์ด ์—†์Šต๋‹ˆ๋‹ค.