n-gram analyzer 를 사용하여 일부 단어를 통해 원하는 검색 결과를 찾는 방법을 한 번 살펴보자.
먼저 아래와 같은 구조로 인덱스를 생성하고자 한다.
es 데이터 예시
{
"_source" : {
"data": {
"essential" : {
"person" : {
"name" : {
"first" : "johnny",
"last" : "wang"
},
"birth" : {
"date" : "2020.01.01"
},
"introduce" : {
"self" : "안녕하세요. 반갑습니다. 조니 왕입니다."
}
}
}
}
}
}
인덱스의 필드 중 "_source.data.essential.person.name.first"와 "_source.data.essential.person.introduce.self" 필드에 n-gram 검색 기능을 적용하고자 한다.
인덱스 생성 시 n-gram 분석 툴을 세팅해주고, 어떤 필드에서 n-gram 을 사용할 것인지를 mapping 쿼리 안에 명시해주어야 한다.
아래 쿼리를 보면 쉽게 이해가 될 것이다.
인덱스 생성 쿼리
# create person index
PUT person-000001
{
"settings": {
"analysis": {
"analyzer": {
"text_ngram_analyzer": {
"tokenizer": "text_ngram_analyzer"
}
},
"tokenizer": {
"text_ngram_analyzer": {
"type": "nGram",
"min_gram": "1",
"max_gram": "30",
"token_chars": [
"letter",
"digit",
"whitespace",
"punctuation"
]
}
}
}
},
"mappings": {
"_doc": {
"properties" : {
"data": {
"properties" : {
"essential" : {
"properties" : {
"person" : {
"properties" : {
"name" : {
"properties" : {
"first" : {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
},
"ngram": {
"type": "text",
"analyzer": "text_ngram_analyzer"
}
}
},
"last" : {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
},
"birth" : {
"properties" : {
"date" : {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
},
"introduce" : {
"properties" : {
"self" : {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
},
"ngram": {
"type": "text",
"analyzer": "text_ngram_analyzer"
}
}
}
}
}
}
}
}
}
}
}
좀 길긴 길지만..;;; 부분적으로 나누어서 보면 쉽게 이해할 수 있습니다... ㅎㅎ... notepad 에 따로 빼서 전체적인 구조를 파악하는 걸 추천!!
먼저 크게는 "settings" 와 "mappings" 로 나눌 수 있는데, "settings" 부분에서는 샤드의 개수나 파이프라인 설정 등 이 인덱스에 적용할 큰 세팅들을 명시해주는 부분이다.
위의 예시에서는 검색을 위한 n-gram 을 설정해주었다.
생성 쿼리를 조금씩 쪼개서 자세히 살펴보자.
"analyzer": {
"text_ngram_analyzer": {
"tokenizer": "text_ngram_analyzer"
}
}
이 부분은 이 analyzer의 이름을 설정하는 부분이다. "text_ngram_analyzer" 부분은 내 마음대로 설정하면 된다.
"tokenizer": {
"text_ngram_analyzer": {
"type": "nGram",
"min_gram": "1",
"max_gram": "30",
"token_chars": [
"letter",
"digit",
"whitespace",
"punctuation"
]
}
}
}
이 부분에서는 내가 생성한 tokenizer 의 설정을 세팅하는 부분이다.
- type : 어떤 툴을 사용하여 텍스트 분석을 할 것인지 (nGram을 사용하겠다)
- min_gram : 단어를 분해할 최소 단위
- max_gram : 단어를 분해할 최대 단위
- token_chars : 어떤 형태의 단어를 토큰화의 기준에 포함할 것인지 (설명 참고 : www.elastic.co/guide/en/elasticsearch/reference/current/analysis-ngram-tokenizer.html)
예시)
만약에 min_gram : 1, max_gram : 5, token_chars : [text, whitespace] 로 설정하고 예시 문장이 "안녕 하세요." 인 경우,
문장은
"안", "녕", " ", "하", "세", "요", "안녕", "녕 ", " 하", "하세", "세요", "안녕 ", ........, "녕 하세요"
로 토큰화된다.
"setting" 부분 다음의 "mapping" 부분은 실제 데이터가 들어갈 필드에 대해 자세히 설정한다.
맨 위의 es 예시 데이터에서 ngram을 적용할 필드는 "name.first" "introduce.self" 이다.
필드 생성에서 내가 설정한 "text_ngram_analyzer"를 사용할 것이라고 설정해준다.
"first" : {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
},
"ngram": {
"type": "text",
"analyzer": "text_ngram_analyzer"
}
}
이렇게 인덱스를 생성한 후 검색에 필요한 es 예시 데이터를 넣어준다.
es에 데이터를 밀어넣는 동시에 ngram 을 설정한 필드는 토큰화 된 모든 단어를 가지고 있다.
내가 설정한 analyzer에 의해서 해당 필드가 어떻게 토큰화 되었는지 확인하기 위한 쿼리는 다음과 같다.
ngram 토큰 검색 쿼리
#ngram 토큰 검색
GET person-000001/_doc/2nv4BXIBdzk5kjug30rM/_termvector?fields=data.essential.person.name.first.ngram
그럼 데이터를 검색해보자. 맨 위에 적은 es 예시 데이터에서 자기소개 부분을 검색해보도록 하겠다.
ngram 데이터 검색 쿼리
#ngram 검색 1
GET 11001-*/_search
{
"from": "0",
"query": {
"bool": {
"must": [
{
"term": {
"data.essetial.person.introduce.self.ngram": {
"value": "안녕하세"
}
}
}
]
}
},
"size": "100",
"sort": [
{
"data.essetial.person.birth": "desc"
}
]
}
bool.must.term 부분에 내가 검색하고자 하는 단어를 입력하면,
es에 저장된 데이터 중 self 필드에 "안녕하세"가 들어간 데이터의 개수와 상세 결과를 리턴받을 수 있다.
그 외에 다른 부분 "from", "size" 는 해당 검색 결과를 0부터 100개까지 출력하겠다는 뜻이고, birth 의 내림차순으로 정렬하여 결과를 보겠다는 뜻이다.
'프로그래밍 > Elasticsearch' 카테고리의 다른 글
[elastic search] mapping 데이터 수정을 위한 reindex (0) | 2021.01.21 |
---|---|
[elastic search] 정규식으로 string replace 하기(_update_by_query) (0) | 2020.12.22 |