본문 바로가기

프로젝트/여행지 오픈 API

[ElasticSearch] 5. 분석기(Analyzer)와 토크나이저, 필터

목차

    분석기(Analyzer)

    엘라스틱 서치는 전문 검색을 지원하기 위해 역인덱싱을 지원한다.

    전문 검색은 장문 문자열에서 부분 검색을 수행하는 것이며, 이 장문의 문자열을 작은 단위(Token)으로 쪼개는 것을 역인덱싱이라고 한다.

    양질의 결과를 위해, 문자열을 나누는 기준이 중요하며(지금까지의 예제인 standard는 일부분이긴 하지만 “ “공백으로 나눴다.), 이를 위해 ‘캐릭터 필터’, ‘토크나이저’, ‘토큰 필터’ 로 구성된 분석기 모듈을 가지고 있다.

     

    캐릭터 필터 : 옵션

    토크나이저 : 반드시 포함

    토큰 필터 : 옵션

     

    개념과 이해

    분석기의 역할은 크게 두 부분으로 나눌 수 있다:

    1. 인덱싱 시: 도큐먼트를 인덱스에 추가할 때, 분석기는 텍스트 필드를 토큰으로 분리하고, 필요한 경우 추가적인 처리(예: 소문자 변환, 불용어 제거 등)를 수행한다. 이렇게 처리된 토큰들이 인덱스에 저장된다.
    2. 검색 시: 사용자가 쿼리문으로 검색을 요청할 때, 분석기는 검색어를 동일한 방식으로 토큰화하고 처리한다. 이렇게 해서 인덱스에 저장된 토큰들과 일치하는 것을 찾는다.

    쉽게 말하면, 분석기는 인덱싱과 검색 과정에서 도큐먼트와 쿼리문의 텍스트를 동일한 방식으로 처리하기 위해 사용된다. 그래서 쿼리문으로 도큐먼트를 검색할 때, 분석기를 통해 처리된 토큰들을 기반으로 매치되는 도큐먼트를 찾는 것이다.

     

    조금 더 쉽게 설명하자면 다음과 같을 것이다.

    1. 분석기는 문장을 여러 조각(토큰)으로 나누는 역할을 한다.
    2. 도큐먼트를 저장할 때, 분석기는 문장을 토큰으로 나눠 저장한다.
    3. 검색을 할 때, 쿼리문도 같은 분석기를 통해 토큰으로 나뉜다.
    4. 이렇게 나뉜 쿼리문의 토큰과 도큐먼트의 토큰이 맞는지 확인해서, 맞는 도큐먼트를 찾아준다.

    정리하자면 인덱싱 과정에서 입력 도큐먼트를 '분석기의 캐릭터 필터, 필터나이저, 토큰 필터' 등으로 전처리하고, 이 저장값을 '쿼리를 통해 나온 토큰' 과 비교한다. 사용자의 쿼리문도 일반적으로는 같은 분석기를 거쳐 토큰화된다.

    분석기 구성

    구성요소 설명

    캐릭터 필터 입력받은 문자열을 변경하거나 불필요한 문자열 제거
    토크나이저 문자열을 토큰으로 분리. 토큰 순서/시작/끝 위치도 기록
    토큰 필터 분리된 토큰의 필터 작업(대소문자 구분, 형태소 분석)
    1. 캐릭터 필터(Character Filter)
      • 목적: 원본 텍스트에 대한 사전 처리를 수행한다.
      • 기능:
        • 특정 문자 또는 문자열을 다른 문자/문자열로 변환. 예를 들면, HTML 엔터티를 해당 문자로 변경.
        • 불필요한 문자나 문자열 제거. 예를 들면, HTML 태그 제거.
      • 사용 사례: HTML 문서에서 태그를 제거하거나 "&"를 "and"로 변경하는 등의 작업.
    2. 토크나이저(Tokenizer)
      • 목적: 텍스트를 개별 토큰으로 분리한다.
      • 기능:
        • 문장 또는 문단을 개별 단어나 구문으로 분리.
        • 각 토큰의 시작과 끝 위치, 순서 등의 정보를 추출.
      • 사용 사례: "Hello, World!" 라는 문장을 ['Hello', 'World']로 토큰화.
    3. 토큰 필터(Token Filter)
      • 목적: 토크나이저로부터 생성된 토큰에 대한 후처리를 수행한다.
      • 기능:
        • 토큰의 대소문자 변환.
        • 불용어(Stop Words) 제거.
        • 형태소 분석을 통한 어근 추출 (예: "running" -> "run").
        • 동의어 처리.
      • 사용 사례: 텍스트에서 "The", "a", "an"과 같은 불용어 제거, "flies"를 "fly"로 변경하는 어근 처리 등.

    기본 분석기와 커스텀 분석기

    이러한 요소를 결합하여 역인덱싱을 수행하는 것이다.

    엘라스틱서치에서 사용하는 분석기(Analyzer)는 크게 기본 분석기와 커스텀 분석기로 나뉜다.

    기본 분석기

    • Standard Analyzer: 가장 일반적으로 사용되며, 텍스트를 공백이나 특수문자 기준으로 나눈다.
    • Simple Analyzer: 문자만 토큰화한다. 텍스트를 공백으로 나누고, 모든 문자를 소문자로 변환한다.
    • Whitespace Analyzer: 공백을 기준으로 텍스트를 나눈다.
    • Keyword Analyzer: 전체 텍스트를 하나의 토큰으로 처리한다.
    • Language Analyzers: 언어별로 특화된 분석기가 있다. 예를 들어, english, french, korean 등.

    커스텀 분석기

    • Custom Analyzer: 사용자가 직접 Char Filter, Tokenizer, Token Filter를 조합하여 만든 분석기.

    토크나이저

    분석기는 반드시 하나의 토크나이저를 포함해야 한다.

    토크나이저는 문자열을 분리해 토큰화하는 역할을 한다. 예시를 하나 살펴보자.

    POST _analyze
    {
      "tokenizer": "uax_url_email",
      "text" : "email: elastic@elk-company.com"
    }

    이메일이나 url이 분리된 모습을 확인할 수 있다.

     

    자주 쓰이는 토크나이저 종류는 다음과 같다.

    standard 스탠다드 분석기가 사용하는 토크나이저. 쉼표나 점 같은 기호를 제거 후 텍스트 기반으로 토큰화
    lowercase 텍스트 기반으로 토큰화하며, 모든 문자를 소문자로 변경한다.
    ngram 원문으로부터 N개의 연속된 글자 단위를 토큰화. ex) “엘라스틱서치”를 2gram으로 토큰화시 [엘라, 라스, 스틱, 틱서, 서치] 거의 모든 조합을 얻어낼 수 있지만, N개 이하의 글자수로는 검색이 불가능하며 조합 수가 많아 저장공간을 많이 차지한다.
    uax_url_email 스탠다드 분석기와 유사하지만 URL이나 이메일 토큰화에 강점을 가진다.

     

    필터

    분석기는 토크나이저와 다수의 필터로 조합된다.

    필터는 옵션이기에 없어도 분석기를 돌리는 데 문제는 없다. 다만 세부적인 작업이 가능하게 하는 데 도움을 준다.

     

    예를 들어, uppercase 필터의 예시를 살펴보자.

    POST _analyze
    {
      "tokenizer": "standard",
      "filter": ["uppercase"],
      "text" : "lowercase Will be UPPERCASE."
    }

    Standared 토크나이저로 분리되며, 필터로 인해 대문자로 변경된다.

     

    필터에는 캐릭터 필터, 토큰 필터가 존재한다.

     

    캐릭터 필터 : 토크나이저 전에 위치하며 문자들을 전처리하는 역할 (&nbsp가 오면 공백으로 바꾸는 등)

    토큰 필터 : 토크나이저에 의해 토큰화된 문자들에 필터를 적용

     

    필터 설명
    lowercase 모든 문자를 소문자로 변환(반대는 uppercase)
    stemmer 영어 문법을 분석하는 필터.
    언어마다 문법이 다르기에 모든 언어에 대응하기는 힘들다.
    한글의 경우 아이랑, 노리 등 오픈소스가 존재한다.
    stop 기본 필터에서 제거하지 못하는 특정 단어 제거

     

    커스텀 분석기

    원하는 분석기가 없을 경우 사용자가 원하는 기능을 직접 만드는 분석기라고 할 수 있을 것이다.

    필터들의 조합이나 순서에 따라 특별한 분석기를 만들어보자.

     

    PUT customer_analyzer
    {
      "settings": {
        "analysis": {
          "filter": { //사용자가 원하는 커스텀 필터를 만들었다.
            "my_stopwords" : { 
              "type" : "stop",
              "stopwords": ["lions"]
            }
          },
          "analyzer": {
            "my_analyzer": {
              "type": "custom",  //커스텀 분석기를 의미한다.
              "char_filter": [], //캐릭터 필터는 사용하지 않았다.
              "tokenizer": "standard", //기본 토크나이저 사용
              "filter": ["lowercase", "my_stopwords"] //소문자 변환과 내 커스텀 필터를 적용했다.
            }
          }
          
        }
      }
    }

     

    생성한 커스텀 분석기를 analyzer를 통해 적용해보자.

     

    GET customer_analyzer/_analyze
    {
      "analyzer": "my_analyzer",
      "text": "lions is can't passed"
    }

     

    lowercase가 적용되고, lions가 내 필터의 stop으로 불용어 처리되어 나오지 않는다.

     

    하지만 필터의 경우, 순서를 적용한다는 점을 고려해야 한다.

    만약 filter의 순서를 바꿔서 실행하면 어떻게 될까?

     

    GET customer_analyzer/_analyze
    {
      "tokenizer": "standard",
      "filter": ["my_stopwords", "lowercase"], 
      "text": "Lions is can't passed"
    }

    lowercase -> 커스텀 필터과 아닌 필터링을 먼저 거치기에, 대문자 Lions가 불용처리되지 않았다.