Dsl

Dsl 카테고리의 모든 포스트 - 한국어

3개의 포스트

Query DSL 정리 (실무 중심)

🔍 1. term 쿼리

{ "term": { "status": "active" } }
  • 정확히 일치하는 값을 찾을 때 사용
  • 형태소 분석되지 않은 필드 (keyword, int, boolean)에 적합
  • text 필드에는 text.keyword로 사용해야 정확히 일치
  • 실무: 상태, ID, 카테고리 코드 등

🔍 2. terms 쿼리

{ "terms": { "status": ["active", "ready"] } }
  • 여러 값 중 하나라도 일치하면 검색
  • IN 조건처럼 사용
  • 65,536개 이상의 값은 사용 불가 (성능 저하)

🔍 3. match 쿼리

{ "match": { "title": "엘라스틱 서치 강의" } }
  • text 필드에 사용
  • 형태소 분석됨 (자연어 검색)
  • 완전 일치 아님 → 관련된 문서도 나올 수 있음

🔍 4. match_phrase 쿼리

{ "match_phrase": { "title": "엘라스틱 서치 강의" } }
  • 정확한 문장 일치 (순서 유지)
  • 중간 단어 빠지면 매칭되지 않음

🔍 5. bool 쿼리

{
  "bool": {
    "must": [ ... ],        // 모두 만족 (AND)
    "should": [ ... ],      // 하나 이상 만족하면 OK (OR 느낌)
    "must_not": [ ... ],    // 만족하면 제외
    "filter": [ ... ]       // 점수 영향 없음, 빠름
  }
}

✔️ 실전 사용 예

{
  "bool": {
    "must": [
      { "term": { "status": "active" } },
      { "match": { "title": "엘라스틱" } }
    ],
    "filter": [
      { "range": { "created_date": { "gte": "now-7d/d" } } }
    ],
    "must_not": [
      { "term": { "is_deleted": true } }
    ]
  }
}

🔍 6. range 쿼리

{ "range": { "price": { "gte": 1000, "lte": 5000 } } }
  • 숫자나 날짜 필드에 범위 조건 적용
  • 실무: 가격, 날짜 필터링

🔍 7. exists 쿼리

{ "exists": { "field": "thumbnail_url" } }
  • 필드가 존재하는지 확인

🔍 8. wildcard / regexp / prefix

{ "wildcard": { "title": "엘라*" } }
  • wildcard, regexp, prefix는 느릴 수 있음
  • analyzed 되지 않은 keyword 필드에 사용 추천

🔍 9. multi_match

{
  "multi_match": {
    "query": "검색어",
    "fields": ["title", "description"]
  }
}
  • 여러 필드에 match 쿼리 적용

🔍 10. script 쿼리

{
  "script_score": {
    "query": { "match_all": {} },
    "script": {
      "source": "doc['click_count'].value * 0.5 + doc['like_count'].value"
    }
  }
}
  • 스크립트 기반 동적 스코어
  • 캐시 안 되고 느릴 수 있음 → 최소 사용 권장

✅ 실무 패턴 정리

목적쿼리
필터링 + 검색bool + must + filter
정확 조건term, terms
자연어 검색match, multi_match
날짜 조건range (filter 사용 권장)
제외 조건must_not
가중치 적용should, script_score
추천 기능should + minimum_should_match

📌 추천 실전 예시

1. 필터 조건 + 본문 검색

{
  "bool": {
    "must": [
      { "match": { "content": "엘라스틱서치 설정법" } }
    ],
    "filter": [
      { "term": { "status": "published" } },
      { "range": { "created_date": { "gte": "now-1M/M" } } }
    ]
  }
}

2. 추천어 기반 검색

{
  "bool": {
    "must": [
      { "term": { "status": "active" } }
    ],
    "should": [
      { "match": { "title": "엘라스틱" } },
      { "match": { "tags": "검색엔진" } }
    ],
    "minimum_should_match": 1
  }
}

⚠️ 주의할 점

  • text 필드에는 term ❌ → .keyword 사용
  • match는 유사도 기반 → 정확 검색은 term
  • filter는 점수 계산 안 함 → 빠름
  • should만 있을 경우 minimum_should_match 설정 안 하면 모두 미일치해도 통과 가능
  • script는 느림
  • wildcard, regexp는 느림 → 되도록 ngram 대체 고려

심화 쿼리 정리 (실무 중심)

1. 🔧 function_score 쿼리

📌 개념

검색 점수(score)에 함수를 적용해서 가중치(weighting)나 랜덤성 부여

✅ 사용 예시

{
  "function_score": {
    "query": { "match": { "title": "엘라스틱" } },
    "functions": [
      {
        "filter": { "term": { "is_premium": true } },
        "weight": 2
      },
      {
        "random_score": {}
      }
    ],
    "boost_mode": "multiply"
  }
}

💡 실무 활용

  • 프리미엄 콘텐츠 우선 노출
  • 추천 콘텐츠 랜덤성 부여
  • 클릭 수, 조회 수 기반 가중치 조정

⚠️ 주의사항

  • 함수마다 성능 차이 큼 (특히 script 포함 시)
  • boost_mode, score_mode 조정 필요

2. 🧮 script_score 쿼리

📌 개념

커스텀 스크립트로 score 직접 계산

페이징 전략 정리 (실무 중심)

✅ 1. 기본 페이징: from + size

🔹 개념

SQL의 OFFSET, LIMIT처럼 특정 위치부터 몇 개를 가져옴.

{
  "query": { "match_all": {} },
  "from": 0,
  "size": 10
}

✅ 특징

  • 가장 기본적인 방법
  • from=0, size=10 → 1페이지, from=10, size=10 → 2페이지

⚠️ 주의사항

  • from이 클수록 성능이 나빠짐 (deep pagination)
  • 기본 최대는 10,000 (index.max_result_window 초과 시 에러)

💡 실무 팁

  • 리스트 조회에는 적합
  • 대용량 페이징에는 search_after 또는 scroll 사용

✅ 2. 안정적인 순차 페이징: search_after

🔹 개념

정렬된 필드 기준으로 커서를 넘겨 다음 페이지 요청