결국 무엇이든 해내는 사람

ElasticSearch - NGram, EdgeNGram, Shingle 토큰 필터 [ 예제, 설명 ] 본문

두서없는 공부 노트/ElasticSearch

ElasticSearch - NGram, EdgeNGram, Shingle 토큰 필터 [ 예제, 설명 ]

kkm8257 2021. 12. 14. 18:30
반응형
-- 용어집 검색과 같이 사용 사례에 따라 텀이 아닌 단어의 일부만 가지고도 검색을 해야하는 경우가 필요
-- like 검색처럼 wildcard 쿼리나 정규식 쿼리도 있지만 이런 쿼리들은 메모리 소모가 많고 느리다
-- 이런 사용을 위해 텀의 일부만 미리 분리해서 저장을 할 수 있는데
-- 이렇게 단어의 일부를 나눈 부위를 NGram 이라고 한다.

-- 설정은 "type" : "nGram"으로 한다.
-- "house"라는 단어를 2글자의 NGram으로 처리하면 "ho","ou","us","se" 총 4개의 토큰들이 추출된다.
-- ngram 토큰필터를 사용하면 이렇게 2글자씩 추출된 텀들이 모두 검색 토큰으로 저장된다.
-- 그렇게 되면 , "ho"라고만 검색을 해도 house가 포함된 도큐먼트들이 검색된다.


-- NGram
-- ngram 토큰 필터에는 옵션이 min_gram과 max_gram 이 있다.
-- 최소, 최대 문자수의 토큰을 구분하는 단위이다.
-- min_gram : 2 , max_gram : 3 로 설정할 경우
-- ho, hou, ou, ous, us, use, se 로 토큰화 된다.


PUT my_ngram
{
  "settings": {
    "analysis": {
      "filter": {
        "my_ngram_f": {
          "type": "nGram",
          "min_gram": 2,
          "max_gram": 3
        }
      }
    }
  }
}


GET my_ngram/_analyze
{
  "tokenizer": "keyword",
  "filter": [
    "my_ngram_f"
  ],
  "text": "house"
}


-- 결과
{
  "tokens" : [
    {
      "token" : "ho",
      "start_offset" : 0,
      "end_offset" : 5,
      "type" : "word",
      "position" : 0
    },
    {
      "token" : "hou",
      "start_offset" : 0,
      "end_offset" : 5,
      "type" : "word",
      "position" : 0
    },
    {
      "token" : "ou",
      "start_offset" : 0,
      "end_offset" : 5,
      "type" : "word",
      "position" : 0
    },
    {
      "token" : "ous",
      "start_offset" : 0,
      "end_offset" : 5,
      "type" : "word",
      "position" : 0
    },
    {
      "token" : "us",
      "start_offset" : 0,
      "end_offset" : 5,
      "type" : "word",
      "position" : 0
    },
    {
      "token" : "use",
      "start_offset" : 0,
      "end_offset" : 5,
      "type" : "word",
      "position" : 0
    },
    {
      "token" : "se",
      "start_offset" : 0,
      "end_offset" : 5,
      "type" : "word",
      "position" : 0
    }
  ]
}




-- Edge NGram
-- 검색을 위해 NGram을 저장해도, 대부분 단어의 맨 앞에서부터 검색하므로, 텀 앞쪽의 ngram 만 저장하기위해서는
-- Edge NGram 토큰필터를 사용
-- 자동완성
-- "type":"edgeNGram" 으로 설정가능
-- 옵션에는 min_gram과 max_gram이 동일하게 있다.
-- house의 경우  ->  h, ho, hou, hous 4개의 토큰이 생성된다.

PUT my_ngram
{
  "settings": {
    "analysis": {
      "filter": {
        "my_ngram_f": {
          "type": "edgeNGram",
          "min_gram": 1,
          "max_gram": 5
        }
      }
    }
  }
}


GET my_ngram/_analyze
{
  "tokenizer": "keyword",
  "filter": [
    "my_ngram_f"
  ],
  "text": "house"
}

-- 결과 출력
{
  "tokens" : [
    {
      "token" : "h",
      "start_offset" : 0,
      "end_offset" : 5,
      "type" : "word",
      "position" : 0
    },
    {
      "token" : "ho",
      "start_offset" : 0,
      "end_offset" : 5,
      "type" : "word",
      "position" : 0
    },
    {
      "token" : "hou",
      "start_offset" : 0,
      "end_offset" : 5,
      "type" : "word",
      "position" : 0
    },
    {
      "token" : "hous",
      "start_offset" : 0,
      "end_offset" : 5,
      "type" : "word",
      "position" : 0
    },
    {
      "token" : "house",
      "start_offset" : 0,
      "end_offset" : 5,
      "type" : "word",
      "position" : 0
    }
  ]
}



-- Shingle
-- NGram 과 Edge NGram은 둘다 하나의 단어로부터 토큰을 확장하는 토큰필터
-- 문자가아니라 단어 단위로 구성된 묶음을 Shingle 이라고한다
-- "type": "shingle"로 적용
-- "hello my computer world" 를 분리할경우
-- hello my, my computer, computer world 이런식으로 분리된다.


-- min과 max를 적절히 조절( 단어 단위 이다 )
PUT my_shingle
{
  "settings": {
    "analysis": {
      "filter": {
        "my_shingle_f": {
          "type": "shingle",
          "min_shingle_size": 3,
          "max_shingle_size": 4
        }
      }
    }
  }
}


-- 출력
GET my_shingle/_analyze
{
  "tokenizer": "whitespace",
  "filter": [
    "my_shingle_f"
  ],
  "text": "this is my sweet home"
}

-- 결과
{
  "tokens" : [
    {
      "token" : "this",
      "start_offset" : 0,
      "end_offset" : 4,
      "type" : "word",
      "position" : 0
    },
    {
      "token" : "this is my",
      "start_offset" : 0,
      "end_offset" : 10,
      "type" : "shingle",
      "position" : 0,
      "positionLength" : 3
    },
    {
      "token" : "this is my sweet",
      "start_offset" : 0,
      "end_offset" : 16,
      "type" : "shingle",
      "position" : 0,
      "positionLength" : 4
    },
    {
      "token" : "is",
      "start_offset" : 5,
      "end_offset" : 7,
      "type" : "word",
      "position" : 1
    },
    {
      "token" : "is my sweet",
      "start_offset" : 5,
      "end_offset" : 16,
      "type" : "shingle",
      "position" : 1,
      "positionLength" : 3
    },
    {
      "token" : "is my sweet home",
      "start_offset" : 5,
      "end_offset" : 21,
      "type" : "shingle",
      "position" : 1,
      "positionLength" : 4
    },
    {
      "token" : "my",
      "start_offset" : 8,
      "end_offset" : 10,
      "type" : "word",
      "position" : 2
    },
    {
      "token" : "my sweet home",
      "start_offset" : 8,
      "end_offset" : 21,
      "type" : "shingle",
      "position" : 2,
      "positionLength" : 3
    },
    {
      "token" : "sweet",
      "start_offset" : 11,
      "end_offset" : 16,
      "type" : "word",
      "position" : 3
    },
    {
      "token" : "home",
      "start_offset" : 17,
      "end_offset" : 21,
      "type" : "word",
      "position" : 4
    }
  ]
}

















반응형
Comments