티스토리 뷰

728x90

안녕하세요. 개발개입니다.

 

위키북스에서 나온 <엘라스틱서치 실무 가이드>를 공부하면서
정리한 부분을 다음과 같은 목차에 따라 공유합니다.

(설치와 관련된 포스트는 많기 때문에 따로 작성하지 않았습니다.)

 

  1. 엘라스틱서치의 이해 (1)

  2. 엘라스틱서치의 이해 (2)

  3. 데이터 모델링

  4. 엘라스틱서치 분석기

  5. 커스텀 분석기

 

이번 글에서는 분석기와 관련하여 다음에 내용에 대해 다룹니다.

목차 
- custom Analyzer

 

오타, 오류 혹은 기타 의견은 언제든지 환영합니다.

 

 

 

 

 


 

custom Analyzer

다음과 같은 커스텀 분석기/필터를 만들어

색인 시, 영화 제목은 movie_title_analyzer, 영화 코멘트는 movie_comment_analyzer를 적용하고

검색 시에는 Standard Analyzer만 사용하는 매핑을 통해 테스트를 진행해 보겠습니다.

 

  • 분석기1
    - 이름 : movie_title_analyzer
    - 토크나이저 : standard analyzer 사용
    - 필터 : uppercase로 변환

  • 분석기2
    - 이름 : movie_comment_analyzer
    - 토크나이저 : standard analyzer 사용
    - 전처리필터 : html_strip (html 태그 제거)
    - 필터 : lowercase로 변환, 커스텀 필터인 english_stopwords 사용

  • 필터
    - 이름 : english_stopwords
    - 불용어 : 영어의 기본적인 불용어 제거

PUT movie_comment
{
  "settings" : {
    "index" : {
      "number_of_shards" : 5,
      "number_of_replicas" : 1
    },
    "analysis" : {
      "analyzer" : {
        "movie_title_analyzer" : {
          "type" : "custom",
          "tokenizer" : "standard",
          "filter" : ["uppercase"]
        },
        "movie_comment_analyzer" : {
          "type" : "custom",
          "tokenizer" : "standard",
          "char_filter" : ["html_strip"],
          "filter" : ["lowercase", "english_stopwords"]
        }
      },
      "filter" : {
        "english_stopwords" : {
          "type" : "stop",
          "stopwords" : "_english_"
        }
      }
    }
  },
  "mappings" : {
    "_doc" : {
      "properties" : {
        "movieCd" : {"type" : "integer"},
        "movieNm" : {"type" : "text", "analyzer" : "movie_title_analyzer", "search_analyzer" : "standard"},
        "comment" : {"type" : "text", "analyzer" : "movie_comment_analyzer", "search_analyzer" : "standard"}
      }
    }
  }
}

 

생성된 인덱스 정보를 확인합니다.

GET movie_comment
{
  "movie_comment" : {
    "aliases" : { },
    "mappings" : {
      "_doc" : {
        "properties" : {
          "comment" : {
            "type" : "text",
            "analyzer" : "movie_comment_analyzer",
            "search_analyzer" : "standard"
          },
          "movieCd" : {
            "type" : "integer"
          },
          "movieNm" : {
            "type" : "text",
            "analyzer" : "movie_title_analyzer",
            "search_analyzer" : "standard"
          }
        }
      }
    },
    "settings" : {
      "index" : {
        "number_of_shards" : "5",
        "provided_name" : "movie_comment",
        "creation_date" : "1584358413075",
        "analysis" : {
          "filter" : {
            "english_stopwords" : {
              "type" : "stop",
              "stopwords" : "_english_"
            }
          },
          "analyzer" : {
            "movie_comment_analyzer" : {
              "filter" : [
                "lowercase",
                "english_stopwords"
              ],
              "char_filter" : [
                "html_strip"
              ],
              "type" : "custom",
              "tokenizer" : "standard"
            },
            "movie_title_analyzer" : {
              "filter" : [
                "uppercase"
              ],
              "type" : "custom",
              "tokenizer" : "standard"
            }
          }
        },
        "number_of_replicas" : "1",
        "uuid" : "mDotPYo6QnWRGBaQFz6BZg",
        "version" : {
          "created" : "6080699"
        }
      }
    }
  }
}

 

샘플 데이터를 인입합니다.

PUT movie_comment/_doc/1
{
  "movieCd" : 1,
  "movieNm" : "eternal sunshine of the spotless mind",
  "comment" : "<h2>It's a surprising</h2>, clever sci-fi twist, even as the relationship drama it dredges up doesn't feel at all like science fiction."
}

PUT movie_comment/_doc/2
{
  "movieCd" : 1,
  "movieNm" : "Eternal Sunshine of the Spotless Mind",
  "comment" : "<strong>Eternal Sunshine of the Spotless Mind</strong> is a whirlwind of emotions, and it is the kind of romance that is just grounded enough, in reality, to inspire and incite, but whimsical enough to deserve its own special place in the genre's history."
}

 

 

결과테스트1 (제목 대소문자구분)

 

영화 제목에 대해 원문과 똑같은 "Sunshine"을 검색해 봅니다.

POST movie_comment/_search
{
  "query" : {
    "term": {
      "movieNm" : "Sunshine"
    }
  }
}
{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 0,
    "max_score" : null,
    "hits" : [ ]
  }
}

 

영화 제목 데이터 인입 시 사용한 movie_title_analyzer는 uppercase 필터가 적용되었기 때문에

"Sunshine"으로 검색할 수 없고 "SUNSHINE"으로 검색해야 합니다.

POST movie_comment/_search
{
  "query" : {
    "term": {
      "movieNm" : "SUNSHINE"
    }
  }
}
{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 2,
    "max_score" : 0.2876821,
    "hits" : [
      {
        "_index" : "movie_comment",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.2876821,
        "_source" : {
          "movieCd" : 1,
          "movieNm" : "Eternal Sunshine of the Spotless Mind",
          "comment" : "<strong>Eternal Sunshine of the Spotless Mind</strong> is a whirlwind of emotions, and it is the kind of romance that is just grounded enough, in reality, to inspire and incite, but whimsical enough to deserve its own special place in the genre's history."
        }
      },
      {
        "_index" : "movie_comment",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 0.2876821,
        "_source" : {
          "movieCd" : 1,
          "movieNm" : "eternal sunshine of the spotless mind",
          "comment" : "<h2>It's a surprising</h2>, clever sci-fi twist, even as the relationship drama it dredges up doesn't feel at all like science fiction."
        }
      }
    ]
  }
}

또는 검색 시에도 uppercase가 적용되도록 하면

"SUNSHINE", "Sunshine", "sunshine"으로 검색해도 모두 결과가 나오게 됩니다.

 

 

 

결과테스트2 (코멘트 불용어제거)

 

영화 코멘트에서 다음과 같은 음영부분을 쿼리 내용으로 하는 검색 쿼리를 날려봅니다.

"Eternal Sunshine of the Spotless Mind is a whirlwind of emotions…"

POST movie_comment/_search
{
  "query" : {
    "query_string": {
      "default_operator": "AND",
      "query" : "whirlwind of emotions"
    }
  }
}

인덱스 내 토큰 : …, [whirlwind], …, [emotions], … (불용어가 제거된 상태)
검색 쿼리 토큰 : [whirlwind] && [of] && [emotions]

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 0,
    "max_score" : null,
    "hits" : [ ]
  }
}

default_operator를 "AND"연산자로 지정했기 때문에 "query"의 토큰들이 모두 포함되어야 합니다.

하지만 인덱스 내 토큰에는 불용어가 제거된 상태로, [of]와 같은 토큰이 존재하지 않기 때문에 결과가 없습니다.

 

"query"에도 불용어를 제거해서 검색하면 어떻게 될까요?

POST movie_comment/_search
{
  "query" : {
    "query_string": {
      "default_operator": "AND",
      "query" : "whirlwind emotions"
    }
  }
}

인덱스 내 토큰 : …, [whirlwind], …, [emothins], … 
검색 쿼리 토큰 : [whirlwind] && [emotions]

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 1,
    "max_score" : 0.5753642,
    "hits" : [
      {
        "_index" : "movie_comment",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 0.5753642,
        "_source" : {
          "movieCd" : 1,
          "movieNm" : "Eternal Sunshine of the Spotless Mind",
          "comment" : "<strong>Eternal Sunshine of the Spotless Mind</strong> is a whirlwind of emotions, and it is the kind of romance that is just grounded enough, in reality, to inspire and incite, but whimsical enough to deserve its own special place in the genre's history."
        }
      }
    ]
  }
}

검색 쿼리의 토큰이 모두 포함되어 있는 문서를 반환하는 것을 알 수 있습니다. 

 

 

 


 

 

 

본 글은 다음을 참고하여 작성되었습니다.

 

권택한 외, 엘라스틱서치 실무가이드, 위키북스

 

 

 

 

 

 

728x90
Total
Today
Yesterday
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
12-25 15:05