본문 바로가기

공부/Elastic

ElasticSearch - Analyzer 기본 설정, Search Analyzer와 비교

ElasticSearch에서 어널라이저(analyzer)는 텍스트 데이터를 분석하고 인덱싱 하기 위해 사용되는 구성 요소이다. 어널라이저는 텍스트를 토큰으로 분리하고, 이를 표준화하고 필터링하여 인덱스에 저장한다. 어널라이저는 주로 세 가지 구성 요소로 구성된다.

 

Tokenizer - 텍스트를 개별 토큰으로 분리함.

 

character filter - 텍스트에 적용되어 분석하기 전에 특정 문자나 패턴을 처리함.

 

token filter - 토큰을 필터링하거나 변환함.

 

 

인덱스 생성 예시

PUT my-index-000001

{
  "aliases": {
    "my_aliases": {}
  },
  "settings": {
    "index": {
      "analysis": {
        "tokenizer": {
          "nori_user_dict": {
            "type": "nori_tokenizer",
            "decompound_mode": "mixed",
            "user_dictionary": "TERMS.txt"
          }
        },
        "filter": {
          "char_filter": {
          	"html_strip": {
            "type": "html_strip"
          },
          "synonyms_filter": {
            "type": "synonym",
            "synonyms_set": "my_synonym_set-1",
            "updateable": true
          },
          "speech_filter": {
            "type": "nori_part_of_speech",
            "stoptags": [
              "E", "IC", "J", "MAG", "MAJ", "MM", "SP",
              "SSC", "SSO", "SC", "SE", "XPN", "XSA", "XSN",
              "XSV", "UNA", "NA", "VSV", "VV", "VX", "VA"
            ]
          },
          "shingle_filter": {
            "type": "shingle",
            "min_shingle_size": 2,
            "max_shingle_size": 2,
            "output_unigrams": true
          },
          "edge_ngram_filter": {
            "type": "edge_ngram",
            "min_gram": 1,
            "max_gram": 10
          }
        },
        "analyzer": {
          "nori_analyzer": {
            "type": "custom",
            "tokenizer": "nori_user_dict",
            "filter": [
              "lowercase",
              "shingle_filter",
              "speech_filter"
            ]
          },
          "search_analyzer": {
            "type": "custom",
            "tokenizer": "nori_tokenizer",
            "filter": [
              "lowercase",
              "speech_filter",
              "synonyms_filter",
              "shingle_filter"
            ]
          },
          "whitespace_analyzer": {
            "type": "whitespace",
            "filter": "speech_filter"
          }
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "content": {
        "type": "text",
        "analyzer": "standard",
        "search_analyzer": "search_analyzer",
        "fields": {
          "nori": {
            "type": "text",
            "analyzer": "nori_analyzer"
          },
          "whitespace": {
            "type": "text",
            "analyzer": "whitespace_analyzer"
          }
        }
      }
    }
  }
}

 

Tokenizer 

예시에는 노리 토크나이저만 정의되어 있음.

"tokenizer": {
  "nori_user_dict": {
    "type": "nori_tokenizer",
    "decompound_mode": "mixed",
    "user_dictionary": "TERMS.txt"
  }

 

노리는 한국어 텍스트를 형태소 단위로 분리하여 토근을 생성한다. 

여기서 사용자 정의 사전을 통해 고유 명사, 전문 용어, 또는 일반적으로 처리되지 않는 단어들을 추가할 수 있다.

 

Character Filter

예시에는 HTML 태그를 제거하는 필터가 정의되어 있음.

"char_filter": {
  "html_strip": {
  "type": "html_strip"
},

 

Token Filter

예시에는 4가지 필터가 정의되어 있음.

 

synonyms_filter - 지정된 동의어 세트를 사용하여 텍스트를 동의어로 대체

 

speech_filter - 지정된 품사 태그를 가진 토큰을 제거하여 불필요한 단어를 필터링

 

shingle_filter - 텍스트를 bigram으로 변환하여 인접한 단어 쌍을 생성

 

edge_ngram_filter - 텍스트의 처음부터 일정 길이의 부분 문자열을 생성하여 부분 단어 검색을 가능하게 함

 

  "synonyms_filter": {
    "type": "synonym",
    "synonyms_set": "my_synonym_set-1",
    "updateable": true
  },
  "speech_filter": {
    "type": "nori_part_of_speech",
    "stoptags": [
      "E", "IC", "J", "MAG", "MAJ", "MM", "SP",
      "SSC", "SSO", "SC", "SE", "XPN", "XSA", "XSN",
      "XSV", "UNA", "NA", "VSV", "VV", "VX", "VA"
    ]
  },
  "shingle_filter": {
    "type": "shingle",
    "min_shingle_size": 2,
    "max_shingle_size": 2,
    "output_unigrams": true
  },
  "edge_ngram_filter": {
    "type": "edge_ngram",
    "min_gram": 1,
    "max_gram": 10
  }

 

 

Analyzer

가장 중요한 Analyzer는 앞서 정의된 토크나이저와 필터로 구성된다.

"analyzer": {
  "nori_analyzer": {
    "type": "custom",
    "tokenizer": "nori_user_dict",
    "filter": [
      "lowercase",
      "shingle_filter",
      "speech_filter"
    ]
  },
  "search_analyzer": {
    "type": "custom",
    "tokenizer": "nori_tokenizer",
    "filter": [
      "lowercase",
      "shingle_filter",
      "speech_filter",
      "synonyms_filter",
    ]
  },
  "whitespace_analyzer": {
    "type": "whitespace",
    "filter": "speech_filter"
  }
}

 

각 어널라이저에 필요한 토크나이저와 필터가 정의되어 있음.

어널라이저 3개 만들어봄 nori_analyzer가 메인이라고 생각하면 된다.

 

(lowercase는 filter에서 정의되어 있진 않지만 모든 토큰을 소문자로 변환하는 필터임)

Search_Analyzer ?

Search_Analyzer는 검색한 내용에 적용되는 Analyzer다. 즉 엘라스틱에 도큐먼트가 추가될 때 작동되는 것이 아니라 특정 검색 쿼리를 수행할 때 어널라이저가 작동된다.

 

예를 들어 "뒷동산"이라는 도큐먼트를 추가하면 nori_analyzer는 "뒷", "동산"으로 분리해 토큰을 저장하게 된다.
(설정에 따라 다르긴 함)

이때  Search_Analyzer 가 없다면 "뒷동산"으로 검색했을 때 "뒷동산"이라는 토큰을 검색한다.

그럼 검색결과에 처음에 추가한 "뒷동산" 도큐먼트는 안 나오게 되는 것이다.

(수정) Search_Analyzer 가 없으면 해당 필드에 적용된 Analyzer가 적용됨.

Search_Analyzer를 적용하면 "뒷동산"을 분석해 나온 결과 "뒷", "동산"이라는 토큰으로 도큐먼트를 검색할 수 있게 된다.

 

synonyms_filter

사실 위 예시보다 Search_Analyzer 가 필요한 더 중요한 이유는 동의어 때문이다.

 

동의어 SET 예시

삼성, 삼성전자, 삼전
현대, 현대차, HD

위와 같이 동의어를 관리한다고 했을 때

analyzer에 동의어 필터를 적용하면 "삼성전자"라는 도큐먼트를 "삼성", "삼성전자", "삼전" 이렇게 동의어까지 같이 토큰으로 저장하게 된다. 

 

마찬가지로 Search_Analyzer에 적용하면 "삼성전자"라는 단어를 검색하면 "삼성", "삼성전자", "삼전" 동의어까지 같이 검색하게 된다.

 

왜 Search_Analyzer에만 synonyms_filter를 설정한 걸까?

3가지 측면이 있다고 본다.

 

인덱싱 속도 - 도큐먼트가 추가될 때 인덱싱 과정에서 동의어를 처리하지 않아 속도가 빨라짐.


인덱싱 크기 - 동의어를 같이 저장하지 않으니 인덱스의 크기가 줄어듦.


동의어 사전 관리 편의성
-> 사실 이게 핵심이라고 생각한다.

만약 analyzer에 동의어 필터를 설정을 하고, 백만 건의 도큐먼트의 인덱싱을 마쳤다고 생각해 보자.

검색 품질을 향상하기 위해 동의어는 변할 수 있고, 새로운 용어가 등장해 업데이트가 필요할 수 도 있다.

 

그런데 위의 상황에서는 동의어 set에 수정이 있으면 반영하기 위해서는 백만 건을 다시 인덱싱 해야 한다... OTL~

Search_Analyzer에

 

Mappings

  "mappings": {
    "properties": {
      "content": {
        "type": "text",
        "analyzer": "standard",
        "search_analyzer": "search_analyzer",
        "fields": {
          "nori": {
            "type": "text",
            "analyzer": "nori_analyzer"
          },
          "whitespace": {
            "type": "text",
            "analyzer": "whitespace_analyzer"
          }
        }

 

위에서 설명한 이유 때문에 content라는 속성에 analyzer와 search_analyzer를 별도로 정의함.

 

추가로 하나의 속성에는 하나의 analyzer만 사용할 수 있는데, multi field를 이용해 여러 개의 analyzer를 사용할 수 있다. 이 방법은 설정한 필드의 개수만큼 중복되기 때문에 인덱스 크기가 뻥튀기될 수 있음에 유의하자.

 

검색 예시

{
  "query": {
    "multi_match": {
      "query": "삼성전자",
      "fields": [
        "content",
        "content.whitespace",
        "content.nori"
      ]
    }
  }
}

 

 

틀린 내용이 있으면 댓글 남겨 주세요!ㅎㅎ

참고

https://www.elastic.co/guide/en/elasticsearch/reference/current/elasticsearch-intro.html

 

What is Elasticsearch? | Elasticsearch Guide [8.13] | Elastic

What is Elasticsearch?edit You know, for search (and analysis) Elasticsearch is the distributed search and analytics engine at the heart of the Elastic Stack. Logstash and Beats facilitate collecting, aggregating, and enriching your data and storing it in

www.elastic.co