Elasticsearch

๊ฒ€์ƒ‰ ์š”๊ตฌ ์‚ฌํ•ญ์„ ์œ„ํ•œ Elasticsearch ์ธ๋ฑ์Šค & Query DSL ์„ค๊ณ„๊ธฐ

์•ˆ์ข…ํ˜ 2025. 5. 2. 17:19

์‚ฌ๋‚ด ์‹ค์Šต์œผ๋กœ ๊ฒ€์ƒ‰ ๊ธฐ๋Šฅ ์š”๊ตฌ์‚ฌํ•ญ์„ ๋ฐ˜์˜ํ•ด Elasticsearch์˜ ์ธ๋ฑ์Šค ์„ค์ •๊ณผ ๋งคํ•‘์„ ์ •์˜ํ•˜๊ณ , ๊ฒ€์ƒ‰์„ ์œ„ํ•œ Query DSL(JSON ๊ธฐ๋ฐ˜ ์ฟผ๋ฆฌ ์–ธ์–ด, Not OpenFeign QueryDSL)์„ ์ž‘์„ฑํ•˜๋ฉด์„œ ๊ณ ๋ฏผํ–ˆ๋˜ ์ ๋“ค์„ ์ •๋ฆฌํ•œ ๊ธ€์ž…๋‹ˆ๋‹ค.

 

๊ฐœ๋ฐœ ํ™˜๊ฒฝ

 

  • VirtualBox (Rocky Linux)
  • Elasticsearch 7.10.2
  • ํ•˜๋‚˜์˜ ํด๋Ÿฌ์Šคํ„ฐ์— ๋…ธ๋“œ 3๊ฐœ ๊ตฌ์„ฑ

 

API ์š”์ฒญ/์‘๋‹ต ๋„๊ตฌ

  • Kibana / Postman

1. ๋ช…์‚ฌ๊ตฌ๊ฐ€ ์ผ์น˜ํ•˜๋Š” ๊ฒฝ์šฐ ๊ฒ€์ƒ‰์ด ๋” ์ž˜๋˜๊ฒŒ ํ•ด์ฃผ์„ธ์š”.

์ด๋ฅผ ์œ„ํ•ด mulit_match ์˜ phrase ํƒ€์ž…์„ ํ™œ์šฉํ–ˆ๋‹ค. multi_match๋Š” type์— ๋”ฐ๋ผ ์ฟผ๋ฆฌ ์‹คํ–‰ ๋ฐฉ๋ฒ•์ด ๋‹ฌ๋ผ์ง„๋‹ค.

 

multi_match ์ฟผ๋ฆฌ์˜ type๋ณ„ ๋™์ž‘

- best_fields (๊ธฐ๋ณธ๊ฐ’)

์—ฌ๋Ÿฌ ํ•„๋“œ ์ค‘ ํ•˜๋‚˜์—์„œ ๊ฒ€์ƒ‰์–ด๊ฐ€ ๊ฐ€์žฅ ์ž˜ ๋งค์น˜๋˜๋Š” ๊ฒฝ์šฐ ํ•ด๋‹น ํ•„๋“œ์˜ ์ ์ˆ˜๋งŒ ์ตœ์ข… _score๋กœ ์‚ฌ์šฉ๋œ๋‹ค.
์˜ˆ๋ฅผ ๋“ค์–ด, title, summary, contents๊ฐ€ ๊ฒ€์ƒ‰ ๋Œ€์ƒ์ผ ๋•Œ, ๊ฒ€์ƒ‰์–ด๊ฐ€ title์—์„œ ๊ฐ€์žฅ ์ž˜ ๋งค์น˜๋˜๋ฉด title ํ•„๋“œ์˜ ์ ์ˆ˜๋งŒ ๋ฐ˜์˜๋œ๋‹ค.

์ฆ‰, "์ œ๋ชฉ์— ํฌํ•จ๋˜์–ด ์žˆ๋‹ค๋ฉด ๊ฐ€์žฅ ์ฐพ๊ธฐ ์‰ฌ์šด ๋ฌธ์„œ"๋ž€ ์š”๊ตฌ์‚ฌํ•ญ์— ์ œ๋ชฉ์— ๊ฐ€์ค‘์น˜๋ฅผ ๋‘์–ด ์‰ฝ๊ฒŒ ๊ตฌํ˜„์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

{
  "query": {
    "multi_match": {
      "query": "์ •๊ธฐํšŒ๋™",
      "type": "best_fields",
      "fields": ["title^5", "summary^2", "contents"]
    }
  }
}

 

์ฐธ๊ณ , best_fields์™€ bool.should ์ฟผ๋ฆฌ์™€์˜ ์ฐจ์ด์ 

bool.should๋กœ ๋™์ผํ•œ ์ฟผ๋ฆฌ๋ฅผ ๊ตฌ์„ฑํ•˜๋ฉด, ์„ธ ํ•„๋“œ์—์„œ์˜ ๋งค์นญ ์ ์ˆ˜๋ฅผ ๋ชจ๋‘ ๋”ํ•œ _score๊ฐ€ ๊ณ„์‚ฐ๋œ๋‹ค. multi_match์˜ best_fields๋Š” ๊ฐ€์žฅ ์ž˜ ๋งค์น˜๋œ ๋‹จ์ผ ํ•„๋“œ์˜ ์ ์ˆ˜๋งŒ ๋ฐ˜์˜๋˜๋Š” ๋ฐ˜๋ฉด, bool.should๋Š” ๋ชจ๋“  ํ•„๋“œ ์ ์ˆ˜๋ฅผ ํ•ฉ์‚ฐํ•œ๋‹ค๋Š” ์ฐจ์ด๊ฐ€ ์žˆ๋‹ค.

"query": {
  "bool": {
    "should": [
      { "match": { "title": "์ •๊ธฐํšŒ๋™" }},
      { "match": { "summary": "์ •๊ธฐํšŒ๋™" }},
      { "match": { "contents": "์ •๊ธฐํšŒ๋™" }}
    ]
  }
}

 

- phrase ํƒ€์ž…

multi_match์—์„œ type: "phrase"๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์•„๋ž˜ ๋‚ด์šฉ์ฒ˜๋Ÿผ match_phrase ์ฟผ๋ฆฌ๊ฐ€ ์‹คํ–‰๋œ๋‹ค. ์ด๋Š” ๋ช…์‚ฌ๊ตฌ๊ฐ€ ์ˆœ์„œ๋Œ€๋กœ ์ผ์น˜ํ•˜๋Š” ๊ฒฝ์šฐ์— ์ ํ•ฉํ•˜๋‹ค.

The phrase and phrase_prefix types behave just like best_fields, but they use a match_phrase or match_phrase_prefix query instead of a match query.

 

์ฒซ ๋ฒˆ์งธ multi_match๋Š” ์ •ํ™•ํ•œ ๋ช…์‚ฌ๊ตฌ ์ผ์น˜์— ๊ฐ€์ค‘์น˜๋ฅผ ์ฃผ๊ณ , ๋‘ ๋ฒˆ์งธ multi_match ๋Š” ์ •ํ™•ํ•œ ๋ช…์‚ฌ๊ตฌ ์ผ์น˜๊ฐ€ ์—†์„ ๊ฒฝ์šฐ ๊ฒ€์ƒ‰์ด ๋˜๊ธฐ ์œ„ํ•œ ์ฟผ๋ฆฌ๋กœ ์ƒ๊ฐํ•˜๋ฉฐ ๋งŒ๋“ค์—ˆ๋‹ค.

{
  "query": {
    "bool": {
      "should": [
        {
          "multi_match": {
            "query": "๊ตญ๋ฏผ์˜ํž˜ ์ฒญ๋…„์ตœ๊ณ ์œ„์› ๊น€์žฌ์›",
            "type": "phrase", 
            "fields": ["title^10", "writer^10", "contents^2"]
          }
        },
        {
          "multi_match": {
            "query": "๊ตญ๋ฏผ์˜ํž˜ ์ฒญ๋…„์ตœ๊ณ ์œ„์› ๊น€์žฌ์›",
            "fields": ["title^5", "writer^5", "contents"]
          }
        }
      ]
    }
  },

 

2. unique filter ์‚ฌ์šฉ ์‹œ ์ฃผ์˜์ 

๋‰ด์Šค ์ž‘์„ฑ์ž๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋‰ด์Šค๋ฅผ ๊ฒ€์ƒ‰ํ•˜๊ณ  ์‹ถ๋‹ค. ์ž‘์„ฑ์ž ํ•„๋“œ์—๋Š” "์ •์•„๋ž€ ๊ธฐ์ž, ๋ฐ•ํ•˜์–€ ๊ธฐ์ž" ๋˜๋Š” "์ •์•„๋ž€ ๊ธฐ์ž"์ฒ˜๋Ÿผ ๊ฐ’์ด ๋“ค์–ด์˜จ๋‹ค.

์ฒ˜์Œ์—๋Š” nori_tokenizer๋ฅผ ์ƒ๊ฐํ–ˆ์ง€๋งŒ nori_tokenizer๋Š” "์ •์•„๋ž€ ๊ธฐ์ž"๋ฅผ "์ •์•„" + "๋ž€"์œผ๋กœ ํ† ํฐํ™”ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ๊ณต๋ฐฑ ๊ธฐ์ค€์œผ๋กœ ํ…€์„ ๋‚˜๋ˆ„๊ณ  ์ผ๋ถ€ ํŠน์ˆ˜๋ฌธ์ž๋ฅผ ์ œ๊ฑฐํ•˜๋Š” standard tokenizer๋ฅผ ์‚ฌ์šฉํ•ด "์ •์•„๋ž€", "๊ธฐ์ž", "๋ฐ•ํ•˜์–€", "๊ธฐ์ž"์™€ ๊ฐ™์€ ํ…€์„ ์ƒ์„ฑํ•˜๋„๋ก ํ–ˆ๋‹ค.

 

์ด ๊ณผ์ •์—์„œ "๊ธฐ์ž"๊ฐ€ ์ค‘๋ณต๋˜๊ธฐ ๋•Œ๋ฌธ์— unique filter๋ฅผ ์ ์šฉํ•˜๋ฉด "๊ธฐ์ž" ํ…€์ด ํ•˜๋‚˜๋งŒ ๋‚จ๋Š”๋‹ค. ์ฒ˜์Œ์—” ์ด ๋ฐฉ์‹์ด ๋” ํšจ์œจ์ ์ด๋ผ๊ณ  ์ƒ๊ฐํ–ˆ๋‹ค.


ํ•˜์ง€๋งŒ ๋ฌธ์ œ๋Š” unique filter๊ฐ€ term์˜ ์œ„์น˜ ์ •๋ณด(position)๋ฅผ ์œ ์ง€ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์ ์ด๋‹ค. ๊ทธ๋ž˜์„œ "์ •์•„๋ž€ ๊ธฐ์ž" ๋˜๋Š” "๋ฐ•ํ•˜์–€ ๊ธฐ์ž"์™€ ๊ฐ™์ด ๋ช…์‚ฌ๊ตฌ ์ „์ฒด๋ฅผ ๋Œ€์ƒ์œผ๋กœ match_phrase ๊ฒ€์ƒ‰์„ ํ•  ๊ฒฝ์šฐ, ๋ช…์‚ฌ๊ตฌ๊ฐ€ ์ผ์น˜ํ•˜๋Š” ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ค์ง€ ์•Š๊ฒŒ ๋œ๋‹ค.

 

๋”ฐ๋ผ์„œ unique filter๋Š” match_phrase ๊ฒ€์ƒ‰์ด ํ•„์š” ์—†๋Š” ํ•„๋“œ์— ์ ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ ์ ˆํ•˜๋‹ค๊ณ  ํŒ๋‹จ์ด ๋˜๋ฉฐ, unique filter ๋Š” ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ฒŒ ๋˜์—ˆ๋‹ค.

 

3. ์ œ๋ชฉ ํ•„๋“œ์— ๊ฒ€์ƒ‰์–ด๊ฐ€ ํฌํ•จ๋œ ๊ฒฝ์šฐ ๊ฐ€์ค‘์น˜ ๋ถ€์—ฌ

์ œ๋ชฉ(title)์— ๊ฒ€์ƒ‰์–ด๊ฐ€ ํฌํ•จ๋˜์—ˆ์„ ๋•Œ ๋” ๋†’์€ ์ ์ˆ˜๋ฅผ ์ฃผ๊ธฐ ์œ„ํ•ด, ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์„ ์ƒ๊ฐํ–ˆ๋‹ค.

 

1. Mappings์—์„œ boost ์„ค์ •ํ•˜๊ธฐ

"mappings": {
  "properties": {
    "title": {
      "type": "text",
      "boost": 10
    }
  }
}

 

2. Query DSL ์—์„œ ํ•„๋“œ๋ณ„ ๊ฐ€์ค‘์น˜ ๋ถ€์—ฌํ•˜๊ธฐ

# ๋‹จ์ผ ํ•„๋“œ ๊ฒ€์ƒ‰ ์‹œ
"match": {
    "title": { 
        "query": "...", 
        "boost": 10 
    }
}

# ์—ฌ๋Ÿฌ ํ•„๋“œ๋ฅผ ๋™์‹œ์— ๊ฒ€์ƒ‰ํ•  ๋–„
"multi_match": {
    "query": "๊ตญ๋ฏผ์˜ํž˜ ์ฒญ๋…„์ตœ๊ณ ์œ„์›",
    "type": "phrase", 
    "fields": ["title^10", "writer^10", "contents^2"]
}

 

๋‚˜๋Š” Query DSL์—์„œ ๊ฐ€์ค‘์น˜๋ฅผ ๋ถ€์—ฌํ•˜๋Š” ๋ฐฉ์‹์„ ์„ ํƒํ–ˆ๋‹ค.
๊ทธ ์ด์œ ๋Š” mappings์ด๋‚˜ settings๋Š” ํ•œ ๋ฒˆ ์ •์˜๋˜๋ฉด ์žฌ์ƒ‰์ธ(reindex) ์—†์ด๋Š” ์ˆ˜์ •ํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. (ํ•„๋“œ ์ถ”๊ฐ€๋Š” ์ œ์™ธ)

 

reindex๋Š” ๊ธฐ์กด ์ธ๋ฑ์Šค์˜ ๋ฌธ์„œ๋ฅผ ์ƒˆ ์ธ๋ฑ์Šค๋กœ ๋‹ค์‹œ ์ƒ‰์ธํ•˜๋Š” ์ž‘์—…์ด๋‹ค.
๋”ฐ๋ผ์„œ title ํ•„๋“œ์˜ ๊ฐ€์ค‘์น˜๋ฅผ 10์—์„œ 20์œผ๋กœ ๋ฐ”๊พธ๋ ค๋Š” ์ƒˆ๋กœ์šด ์š”๊ตฌ์‚ฌํ•ญ์ด ์ƒ๊ฒผ์„ ๋•Œ, ๊ธฐ์กด mappings์— boost ๊ฐ’์„ ์„ค์ •ํ•ด๋’€๋‹ค๋ฉด ์œ ์—ฐํ•˜๊ฒŒ ๋Œ€์‘ํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

 

4. ๊ฒ€์ƒ‰ ํ•„๋“œ์ธ '์ œ๋ชฉ'์„ ๊ธฐ์ค€์œผ๋กœ ์ •๋ ฌํ•ด ์ฃผ์„ธ์š”.

์ œ๋ชฉ์€ ๊ฒ€์ƒ‰ ๋Œ€์ƒ์ด์ž ์ •๋ ฌ ๊ธฐ์ค€์ด ๋˜์–ด์•ผ ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์—, multi-fields๋ฅผ ์‚ฌ์šฉํ•ด ํ•ด๊ฒฐํ–ˆ๋‹ค.

 

๋จผ์ €, ๊ฒ€์ƒ‰ ๋Œ€์ƒ์ธ ์ œ๋ชฉ์„ ์ƒ‰์ธํ•˜๊ธฐ ์œ„ํ•ด์„œ ์ œ๋ชฉ ํ•„๋“œ๋ฅผ mappings ์— ์• ๋„๋ผ์ด์ €์™€ text ํƒ€์ž…์„ ์ •์˜ํ•˜๊ฒŒ ๋œ๋‹ค.

 "mappings": {
    "properties": {
      ...
      "title": {  
        "type": "text",
        "analyzer": "korean_basic_analyzer" // custom ์• ๋„๋ผ์ด์ €
      }
}

 

ํ•˜์ง€๋งŒ text ํƒ€์ž…์€ ์ •๋ ฌ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.
๊ทธ ์ด์œ ๋Š” ์ƒ‰์ธ ์‹œ ์• ๋„๋ผ์ด์ €๋ฅผ ํ†ตํ•ด ํ…์ŠคํŠธ๊ฐ€ ํ† ํฐํ™”๋˜๊ณ , ๊ฒฐ๊ณผ์ ์œผ๋กœ ์—ญ์ƒ‰์ธ ๊ตฌ์กฐ๋กœ ์ €์žฅ๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
์˜ˆ๋ฅผ ๋“ค์–ด "๋ผ๋ฉด"์ด ํฌํ•จ๋œ ๋ฌธ์„œ๊ฐ€ 1, 2, 3๋ฒˆ์ผ ๊ฒฝ์šฐ, ์„ธ ๋ฌธ์„œ ๋ชจ๋‘ "๋ผ๋ฉด"์ด๋ผ๋Š” ํ…€์„ ๊ฐ–๊ณ  ์žˆ์–ด ์–ด๋–ค ๊ธฐ์ค€์œผ๋กœ ์ •๋ ฌํ• ์ง€ ์•Œ ์ˆ˜ ์—†๋‹ค. ์ด ๊ฒฝ์šฐ Elasticsearch๋Š” _score ๊ธฐ์ค€์œผ๋กœ๋งŒ ์ •๋ ฌํ•˜๊ฒŒ ๋œ๋‹ค.

 

์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด title ํ•„๋“œ๋ฅผ ๋ฉ€ํ‹ฐ ํ•„๋“œ๋กœ ์„ค์ •ํ•ด keyword ํƒ€์ž…์„ ์ถ”๊ฐ€ํ–ˆ๋‹ค. keyword๋Š” ํ† ํฐํ™”๋ฅผ ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ •๋ ฌ ๊ธฐ์ค€์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. keyword ํƒ€์ž…์˜ ํ•„๋“œ๋Š” ์• ๋„๋ผ์ด์ € ๋Œ€์‹  ๋…ธ๋ฉ€๋ผ์ด์ €๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ, ๋…ธ๋ฉ€๋ผ์ด์ €๋Š” ํ† ํฌ๋‚˜์ด์ €๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

 

์ด๋ ‡๊ฒŒ title ์„ title.text ์™€ title.keyword ๋กœ multi_fields๋ฅผ ๋‘”๋‹ค๋ฉด ์ด ๋‘ ํ•„๋“œ๋Š” ์™„์ „ํžˆ ๋ณ„๊ฐœ๋กœ ๋™์ž‘ํ•˜๊ฒŒ ๋œ๋‹ค. 

 "mappings": {
    "properties": {
      ...
      "title": {  
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword"
          }
        },
        "analyzer": "korean_basic_analyzer" // custom ์• ๋„๋ผ์ด์ €
      }
}

 

๊ทธ๋ฆฌ๊ณ , Query DSL ์ž‘์„ฑ ์‹œ, sort์— title.keyword ํ•„๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ๋œ๋‹ค.

 "sort": [
    { "title.keyword": "asc" }
  ]

 

๊ทธ๋Ÿฌ๋‚˜, ์ด๋ ‡๊ฒŒ ํ•„๋“œ๊ฐ€ ๊ฒ€์ƒ‰ ๋Œ€์ƒ์ด๋ฉด์„œ, keyword ๋ฅผ ํ™œ์šฉํ•ด ์ •๋ ฌํ•˜๋ฉด score ๊ธฐ๋ฐ˜์ด ๋ฌด์‹œ๋˜์–ด ๋ฌธ์„œ ๊ฒ€์ƒ‰ ์ •ํ™•๋„๊ฐ€ ๋–จ์–ด์ง€๊ฒŒ ๋œ๋‹ค.

๊ทธ๋ž˜์„œ, ์ •๋ ฌ์ด ํ•„์š”ํ•˜๋‹ค๋ฉด ๊ฒ€์ƒ‰ ๋Œ€์ƒ์œผ๋กœ ์ •๋ ฌํ•˜๊ธฐ ๋ณด๋‹ค๋Š” ํ† ํฐํ™” ๋˜์ง€ ์•Š๋Š” ํ•„๋“œ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์ •๋ ฌํ•˜๋Š” ์š”๊ตฌ์‚ฌํ•ญ์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋ฉด ์ข‹์„ ๋“ฏ ํ•˜๋‹ค.

 

์ถ”๊ฐ€๋กœ ๊ณต์‹๋ฌธ์„œ์—์„œ ๋ฉ€ํ‹ฐ ํ•„๋“œ๋Š” ๊ฐ™์€ ํ•„๋“œ๋ฅผ ์—ฌ๋Ÿฌ ์• ๋„๋ผ์ด์ €๋ฅผ ํ™œ์šฉํ•ด ๊ฒ€์ƒ‰ ์ •ํ™•๋„๋ฅผ ๋†’์ด๋Š”๋ฐ๋„ ์‚ฌ์šฉ๋œ๋‹ค๊ณ  ํ•œ๋‹ค.

* Multi-fields with multiple analyzers 

 

5. ๊ฒ€์ƒ‰ ๋Œ€์ƒ์ด ์•„๋‹Œ ํ•„๋“œ๋Š” ์• ๋„๋ผ์ด์ € ๋Œ€์‹  ๋…ธ๋ฉ€๋ผ์ด์ € ์‚ฌ์šฉ

์• ๋„๋ผ์ด์ €๋Š” 0~3๊ฐœ์˜ Character Filter, 1๊ฐœ์˜ Tokenizer, 0~n๊ฐœ์˜ Token Filter ๋กœ ๊ตฌ์„ฑ๋œ๋‹ค.

ํ•˜์ง€๋งŒ, ๋…ธ๋ฉ€๋ผ์ด์ €๋Š” Tokenizer๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์—†๋‹ค. ๋‹ค์‹œ ๋งํ•ด ๊ฒ€์ƒ‰ ๋Œ€์ƒ์ด ์•„๋‹Œ ํ•„๋“œ๋Š” ๋…ธ๋ฉ€๋ผ์ด์ €๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

 

์˜ˆ๋ฅผ ๋“ค์–ด, ๋…ธ๋ฉ€๋ผ์ด์ €๋Š” "์šฐ๋ฆฌ์˜ ๋ชฉํ‘œ๋Š” ํ–‰๋ณตํ•˜๊ธฐ ์ž…๋‹ˆ๋‹ค." ๋ฅผ ์ €์žฅํ•  ๋•Œ, "์šฐ๋ฆฌ" "๋ชฉํ‘œ" "ํ–‰๋ณต" ์ด๋ ‡๊ฒŒ ํ† ํฐํ™”ํ•˜์ง€ ์•Š๊ณ , " ์šฐ๋ฆฌ์˜ ๋ชฉํ‘œ๋Š” ํ–‰๋ณตํ•˜๊ธฐ ์ž…๋‹ˆ๋‹ค. " ์ด ๋ฌธ์žฅ ์ž์ฒด๋กœ ์ €์žฅ์„ ํ•œ๋‹ค. ๊ทธ๋ž˜์„œ, ์ •ํ™•ํžˆ ์ผ์น˜ํ•˜๋Š” term์ฟผ๋ฆฌ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ณ , keyword ํƒ€์ž… ์‚ฌ์šฉ ์‹œ, ๋…ธ๋ฉ€๋ผ์ด์ €๋ฅผ ํ™œ์šฉํ•˜๊ฒŒ ๋œ๋‹ค.

 

6. ์ธ๋ฑ์Šค ์„ค์ • ์‹œ, dynamic: false ์‚ฌ์šฉ ์•ˆํ•˜๊ธฐ

Elasticsearch๋Š” ๋ฌธ์„œ๋ฅผ ์ƒ‰์ธํ•  ๋•Œ, ์ธ๋ฑ์Šค์— ์ •์˜๋˜์ง€ ์•Š์€ ํ•„๋“œ๊ฐ€ ์žˆ์œผ๋ฉด ์ž๋™์œผ๋กœ ํ•„๋“œ์˜ ํƒ€์ž…์„ ์ถ”๋ก ํ•ด์„œ ํ•„๋“œ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.

ํ•˜์ง€๋งŒ, Elasticsearch ๋„ ํ•„๋“œ์˜ ํƒ€์ž…์„ ์ง€์ •ํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. ์ž๋ฃŒํ˜•์ด ์ ์€(์ž๋ฃŒํ˜•์— ์•Œ๋งž๋Š”) ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๋ฉด ๊ฒ€์ƒ‰/์ƒ‰์ธ ์‹œ ์„ฑ๋Šฅ์ด ์ข‹์•„์ง„๋‹ค.(16๋น„ํŠธ๋กœ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ’์ด๋ฉด integer ๋ณด๋‹ค๋Š” short ๋กœ ์ง€์ •ํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค๋Š” ์˜๋ฏธ)

๋‹ค๋งŒ, ์ €์žฅํ•  ๋•Œ๋Š” ์‹ค์ œ ๊ฐ’์— ๋งž์ถฐ ์ตœ์ ํ™” ๋˜์–ด ๋””์Šคํฌ ์‚ฌ์šฉ๋Ÿ‰์—์„œ์˜ ์ด๋“์€ ์—†๋‹ค๊ณ  ํ•œ๋‹ค.(์ถœ์ฒ˜. ์—˜๋ผ์Šคํ‹ฑ ๋ฐ”์ด๋ธ”)


์•„๋ฌดํŠผ, mappings ์„ค์ •์— dynamic: false๋ฅผ ์ง€์ •ํ•˜๋ฉด ํƒ€์ž…์ด ์ •์˜๋˜์ง€ ์•Š์€ ํ•„๋“œ๋Š” ํƒ€์ž…์„ ์ถ”๋ก ํ•˜์ง€ ์•Š๊ณ  ์ƒ‰์ธ๋˜์ง€ ์•Š๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ค. 

ํ•˜์ง€๋งŒ, dynamic: false ๋Š” ์ƒˆ๋กœ์šด ํ•„๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ ๋˜ํ•œ ๋ถˆ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋งŒ๋“ ๋‹ค. ์ฆ‰, "๋‚˜์ค‘์— ํŠน์ • ํ•„๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  ์‹ถ์–ด์š”" ๋ž€ ์š”๊ตฌ์‚ฌํ•ญ์— ๋Œ€์‘ํ•˜๊ธฐ ์–ด๋ ต๊ฒŒ ๋œ๋‹ค.

 

๋”ฐ๋ผ์„œ ๋ถˆํ•„์š”ํ•œ ํ•„๋“œ ์ƒ์„ฑ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด dynamic: false๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋Œ€์‹ , ๋ฌธ์„œ ์ „์ฒ˜๋ฆฌ ๊ณผ์ •์—์„œ ํ•„์š”์—†๋Š” ํ•„๋“œ๋ฅผ ์ •์ œํ•ด์ฃผ๋Š” ๊ฒƒ์ด ๋” ๋‚˜์€ ๋ฐฉ์‹์ด๋ผ๊ณ  ์ƒ๊ฐํ•œ๋‹ค.

 

7. ๊ธฐํƒ€

- ๋‚ ์งœ ํ•„๋“œ๋Š” format ์˜ต์…˜์„ ๋ช…์‹œํ•ด์„œ ์ฒ˜๋ฆฌ

- ์ง‘๊ณ„(aggregation)๋ฅผ ์œ„ํ•ด aggs ์‚ฌ์šฉ

- text ํƒ€์ž…์€ ์ง‘๊ณ„๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•˜๋ฏ€๋กœ, ์ง‘๊ณ„๋ฅผ ์œ„ํ•ด multi-fields๋กœ keyword ํƒ€์ž…์„ ๋ณ‘ํ–‰ ์‚ฌ์šฉ

- ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ๊ฐ•์กฐ๋ฅผ ์œ„ํ•ด highlight ์‚ฌ์šฉ

 

 

๋งˆ์น˜๋ฉฐ

์ด๋ฒˆ ์ž‘์—…์„ ํ•˜๋ฉฐ ๋ถ€์กฑํ–ˆ๋˜ ์ ๋„ ์žˆ์—ˆ๋‹ค.
์˜ˆ๋ฅผ ๋“ค์–ด, ํด๋Ÿฌ์Šคํ„ฐ 1๊ฐœ์— ๋…ธ๋“œ 3๊ฐœ๋ฅผ ๊ตฌ์„ฑํ–ˆ์„ ๋•Œ, ์ธ๋ฑ์Šค๋ฅผ ๋ช‡ ๊ฐœ์˜ ์ƒค๋“œ๋กœ ๋ถ„์‚ฐ์‹œํ‚ฌ์ง€ ๊ธฐ์ค€์„ ๋ช…ํ™•ํžˆ ์„ธ์šฐ์ง€ ๋ชปํ–ˆ๋‹ค.

  • number_of_shards : ํ•ด๋‹น ์ธ๋ฑ์Šค๋ฅผ ๋ช‡ ๊ฐœ์˜ ์ƒค๋“œ๋กœ ์ชผ๊ฐค๊ฑด์ง€ ์„ค์ • ๊ฐ’์ด๋‹ค.
    • ์ƒค๋“œ ์ˆ˜๊ฐ€ ๋„ˆ๋ฌด ๋งŽ์œผ๋ฉด ๋ฌธ์„œ ์ƒ‰์ธ ์„ฑ๋Šฅ์ด ๊ฐ์†Œํ•˜๊ณ , ์ƒค๋“œ ์ˆ˜๊ฐ€ ๋„ˆ๋ฌด ์ž‘์œผ๋ฉด ํ•œ ์ƒค๋“œ์˜ ํฌ๊ธฐ๊ฐ€ ์ปค์„œ ์žฅ์• ๋กœ ์ธํ•œ ์ƒค๋“œ ๋ณต๊ตฌ ์‹œ ์˜ค๋ž˜ ๊ฑธ๋ฆผ / ํด๋Ÿฌ์Šคํ„ฐ ์•ˆ์ •์„ฑ์ด ๋–จ์–ด์ง„๋‹ค.
  • numbers_of_replicas : ์ฃผ ์ƒค๋“œ ํ•˜๋‚˜๋‹น ๋ณต์ œ๋ณธ ์ƒค๋“œ ๋ช‡ ๊ฐœ ๋งŒ๋“ค์ง€๋ฅผ ์„ค์ •ํ•œ๋‹ค.

์ด ๋‘ ์„ค์ •์€ ํด๋Ÿฌ์Šคํ„ฐ ์šด์˜ ์‹œ ์ •๋ง ํ•„์š”ํ•œ ์„ค์ •์ด๊ธฐ ๋•Œ๋ฌธ์— ๊ผญ ์ถ”ํ›„์— ํ•™์Šตํ•˜๊ณ ์ž ํ•œ๋‹ค.

 

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

๊ทธ๋ž˜์„œ ์ ์  ๋А๋ผ๋Š” ๊ฑด, ์ƒˆ๋กœ์šด ๊ธฐ์ˆ ์„ ๋ฐฐ์šธ ๋•Œ์—๋Š” ํ•„์š”ํ•œ ๊ฒƒ์„ ์œ„์ฃผ๋กœ ์‚ฝ์งˆ์„ ํ•ด์•ผ ๋จธ๋ฆฌ์— ์˜ค๋ž˜ ๋‚จ๋Š”๊ฒƒ์„ ๋А๊ผˆ๋‹ค. ์ƒˆ๋กœ์šด ๊ธฐ์ˆ ์„ ๋ฐฐ์šธ ๋•Œ์—๋Š” ํ•„์š”ํ•œ ๋ถ€๋ถ„๋ถ€ํ„ฐ ์ฐจ๊ทผ์ฐจ๊ทผ ๋ฐฐ์šฐ๊ณ , ์ ˆ๋Œ€์ ์ธ ์‹œ๊ฐ„๋„ ํ•„์š”ํ•˜๋‹ค๋Š” ๊ฒƒ์„ ์ƒ๊ฐํ•˜๋ฉฐ ์กฐ๋ฐ”์‹ฌ ๋‚ด์ง€ ์•Š๋Š” ๊ฒƒ๋„ ์ค‘์š”ํ•œ ๊ฒƒ ๊ฐ™๋‹ค.