오타 교정 기능 적용 이후 검색 결과 정확도 향상을 위한 인덱스 매핑 변경 과정-①

Ariul·2022년 10월 5일
1
post-thumbnail

6주 동안 실전 프로젝트를 진행하면서 학습한 내용을 기록하고, 팀의 리더로서 프로젝트 매니징 경험을 기록하는 시리즈입니다.


오타 교정 기능 적용

검색 서비스의 기본 요구 사항 중 하나는 ‘오타 교정’ 기능입니다. 심지어 초보자를 위한 특허 검색 서비스라면 ‘오타 교정’ 기능이 필수적이라 생각하여 기능을 추가하였습니다.

문제 발생

하지만 '오타 교정' 기능을 구현한 뒤로 검색 결과 정확도가 저하되거나 검색 결과가 누락되는 문제가 있었습니다.

문제 원인

  1. Nori 애널라이저에 fuzziness 적용
  2. 인덱스 텀과 쿼리 텀의 불일치

문제 해결

  1. 660만 개의 용어가 담긴 사용자 정의 사전 적용
  2. 필드별 색인, 검색 애널라이저 분리
  3. Edge n-gram 애널라이저를 Ngram 애널라이저로 변경

v1, v2, v3, v4 한눈에 비교하기

v1. Nori + Jamo 필터 +edge-Ngram 필터v2. Nori, Jamo, Edge n-gram+ 사용자 사전v3. Nori + Jamo + N-gram + 사용자 사전v4. Nori + Jamo + N-gram
storage size56.87mb65.47mb70.9mb69.1mb
추가 및 변경 사항1) 필드별 색인 애널라이저 분리 2) 필드별 검색 애널라이저 분리 3) 사용자 정의 사전 추가1) Edge n-gram 애널라이저를 Ngram 애널라이저로 변경1) 사용자 정의 사전을 적용하지 않음
원문 키워드 검색 시 결과 반환
띄어쓰기 변화 시 결과 반환
오타 교정 결과 반환❌ (결과 누락)

다음은 사용자 정의 사전 적용 과정 및 4단계의 인덱스 정의 테스트 과정을 자세히 담은 내용입니다.


v1. Nori + Jamo 필터 + edge-Ngram 필터

인덱스 매핑 정의

PUT nori-plus-jamo-edge-filters
{
  "settings": {
    "analysis": {
      "char_filter": { // 1️⃣ 캐릭터 필터
        "special_character_filter": {
          "pattern": "[\\p{Alpha}\\p{Digit}\\p{Blank}]",
          "type": "pattern_replace",
          "replacement": ""
        }
      },
      "tokenizer": { // 2️⃣ 토크나이저
        "korean_nori_tokenizer": {
          "type": "nori_tokenizer",
          "decompound_mode": "mixed"
        }
      },
      "filter": { // 3️⃣ 토큰 필터
        "nori_posfilter": {
          "type": "nori_part_of_speech",
          "stoptags": ["J","E","NNB","MAJ","MM","XSV","XSA","VCP","SE","XSN","VCN","SP","NA","UNA","VSV","XPN","IC","VV"]
        },
        "ngram2_filter": {
          "type": "edge_ngram",
          "min_gram": 2,
          "max_gram": 15
        }
      },
      "analyzer": { // 4️⃣ 애널라이저
        "nori_analyzer": {
          "type": "custom",
          "tokenizer": "korean_nori_tokenizer",
          "filter" : [
            "lowercase", 
            "nori_posfilter"
          ]
        },
        "jamo_index_analyzer": {
          "type": "custom",
          "char_filter": [
            "special_character_filter"
          ],
          "tokenizer": "korean_nori_tokenizer",
          "filter": [
            "nori_posfilter",
            "jamo",
            "ngram2_filter"
          ]
        },
        "jamo_search_analyzer": {
          "type": "custom",
          "char_filter": [
            "special_character_filter"
          ],
          "tokenizer": "standard",
          "filter": [
            "jamo"
          ]
        },
        "number_analyzer" : {
          "type" : "pattern",
          "pattern" :"[.]"
        }
      }
    }
  },
  "mappings": { // 5️⃣ 필드에 데이터 타입 매핑
    "properties": {
      "발명의명칭": {
        "type": "text",
        "analyzer": "nori_analyzer",
        "fields": {
          "raw": {
            "type": "keyword",
            "ignore_above": 256
          },
          "spell": {
            "type": "text",
            "analyzer": "jamo_index_analyzer",
            "search_analyzer": "jamo_search_analyzer"
          }
        }
      },
      "요약": {
        "type": "text",
        "analyzer": "nori_analyzer",
        "fields": {
          "spell": {
            "type": "text",
            "analyzer": "jamo_index_analyzer",
            "search_analyzer": "jamo_search_analyzer"
          }
        }
      },
      "출원인": {
        "type": "text",
        "analyzer": "nori_analyzer",
        "fields": {
          "raw": {
            "type": "keyword",
            "ignore_above": 256
          },
          "spell": {
            "type": "text",
            "analyzer": "jamo_index_analyzer",
            "search_analyzer": "jamo_search_analyzer"
          }
        }
      },
      "CPC분류": {
        "type": "text"    
      },
      "IPC분류": {
        "type": "text"    
      },
      "event": {
        "properties": {
          "original": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          }
        }
      },
      "log": {
        "properties": {
          "file": {
            "properties": {
              "path": {
                "type": "text",
                "fields": {
                  "keyword": {
                    "type": "keyword",
                    "ignore_above": 256
                  }
                }
              }
            }
          }
        }
      },
      "공개번호": {
        "type": "keyword"      
      },
      "공고번호": {
        "type": "keyword"
      },
      "등록번호": {
       "type": "keyword"
      },
      "법적상태": {
        "type": "keyword" 
      },
      "출원번호": {
        "type": "text",
        "fields": {
          "keyword" : {
            "type" : "keyword",
            "ignore_above": "256"
          }
        } 
      },
      "출원일자": {
        "type": "text",
        "analyzer": "number_analyzer",
        "fields": {
          "keyword" : {
            "type" : "keyword",
            "ignore_above" : 256
          }
        }
      }
    }
  }
}

1. Character Filter

1.1. Pattern Replace Character Filter

정규 표현식을 사용하여 해당 문자들을 특정 문자열로 대체합니다.

pattern replace character filter가 제공하는 옵션은 다음과 같습니다.

  • pattern : 자바 정규 표현식
    표현식의미
    \p{Alpha}문자
    \p{Digit}숫자
    {Blank}space 또는 tab
  • replacement : 대체 문자열 ⇒ 문자, 숫자, 공백이 사라지게 됩니다.

2. Tokenizer

2.1. Nori Tokenizer

nori_tokenizer가 제공하는 옵션은 다음과 같습니다.

  • user_dictionary : 사용자 정의 사전 ⇒ 특허 검색 서비스의 경우, 사용자 정의 사전은 설정하기 어렵다고 판단하여 배제하였습니다.
  • decompound_mode : 복합 명사를 토크나이저가 처리하는 방식을 결정 ⇒ 분리된 복합 명사와 원본 데이터 모두 유지하기 위해 mixed로 설정하였습니다.

3. Token Filter

3.1. nori_part_of_speech

nori_part_of_speech 토큰 필터를 이용해서 제거할 품사(POS - Part Of Speech) 코드입니다.

태그설명태그설명태그설명
E어미IC감탄사J조사
MAJ접속 부사MM한정사NA알 수 없음
NNB의존명사SE줄임표SP공백
UNA알 수 없음VCN부정 지정사VCP긍정 지정사
VSV알 수 없음XPN접두사XSA형용사 파생 접미사
XSN명사 파생 접미사XSV동사 파생 접미사VV동사

3.2. edge_ngram

edge-ngram token filter가 제공하는 옵션은 다음과 같습니다.

  • min_gram: 그램의 최소 글자 수
  • max_gram: 그램의 최대 글자 수

4. Analyzer

4.1. nori_analyzer

[발명의명칭], [출원인], [요약] 필드의 데이터에 한글 형태소 분석기(Nori)를 적용하였습니다.

4.2. jamo_index_analyzer

[발명의명칭], [요약], [출원인] 필드를 멀티 필드로 두고 .spell 필드에 커스텀 애널라이저를 적용하였습니다.

이 커스텀 애널라이저는 캐릭터 필터를 통해 문자, 숫자, 공백을 제거하고 nori 토크나이저와 jamo, edge n-gram 필터를 사용합니다.

4.3. jamo_search_analyzer

jamo_index_analyzer로 색인된 용어들을 잘 찾기 위해 검색 시에 search analyzer를 적용하였습니다.

이 커스텀 애널라이저는 캐릭터 필터를 통해 문자, 숫자, 공백을 제거하고 standard 토크나이저와 jamo 필터를 사용합니다.

4.4. number_analyzer

[출원일자] 필드의 데이터는 ‘2022.09.21’의 형태를 가집니다.

그 중에서 연도(2022)만 추출하기 위해 패턴 “[.]”을 기준으로 텍스트를 분리하는 패턴 애널라이저를 적용했습니다.

5. 필드에 데이터 타입 매핑

  • [출원번호] : text, keyword
  • [출원일자] : text, keyword
  • [발명의명칭] : text, keyword
  • [출원인] text, keyword
  • [IPC분류] text
  • [CPC분류] text
  • [공고번호] keyword
  • [공개번호] keyword
  • [등록번호] keyword
  • [법적상태] keyword
  • [요약] text

문제점

  • Nori가 품사를 잘못 정의하고 잘라내는 문제

    • 검색한 키워드: 오일저장탱크
    • 예상 반환 결과:
    • 실제 반환 결과: 검색 결과 없음
      {
        "took": 5,
        "timed_out": false,
        "_shards": {
          "total": 1,
          "successful": 1,
          "skipped": 0,
          "failed": 0
        },
        "hits": {
          "total": {
            "value": 0,
            "relation": "eq"
          },
          "max_score": null,
          "hits": []
        }
      }
    • 검색 결과가 없는 이유: Nori가 품사를 잘못 정의하여 오일 로 잘라내기 때문
  • 인덱스텀과 쿼리텀이 일치하지 않는 문제

    • jamo_index_analyzer로 만든 인덱스텀
      • ㅇㅗ , ㅇㅣ , ㅇㅣㄹ
    • jamo_search_analyzer로 만든 쿼리텀
      • ㅇㅗㅇㅣㄹㅈㅓㅈㅏㅇㅌㅐㅇㅋㅡㄹㅡㄹ

해결 방법 및 대안

  • Nori 사용하지 않고 jamo 필터와 edge-Ngram 필터로만 매핑 시도
    • Nori가 품사를 잘못 정의하는 문제는 저희가 해결할 수 없는 문제라고 판단하여 Nori를 jamo 필터와 edge-Ngram 필터로만 매핑했습니다.
    • 그 결과, storage size가 2배 이상 증가한다는 것을 확인하였습니다.
      • storage size: 56.87mb → 133.64mb
  • Nori를 사용하지 않으면 POS 토큰 필터로 무수히 많은 불용어를 제거할 수 있는 이점을 취할 수 없었습니다.
  • Nori의 POS 토큰 필터의 효과를 얻음과 동시에 side effect를 줄이기 위해서는 사용자 정의 사전 사용이 필수적이라 판단하였습니다.
  • 지속적으로 서치한 결과 한국특허정보원에서 개발한 언어모델 KorPatELECTRA를 찾을 수 있었고, 신청을 통해 사용 허가를 받은 후 사용자 정의 사전을 적용하였습니다. 👉 kipi-ai/korpatbert

v2. Nori + Jamo + Edge n-gram + 사용자 사전

인덱스 매핑 정의

PUT user-dic-plus
{
  "settings": {
    "analysis": {
      "char_filter": { // 1️⃣ 캐릭터 필터
        "special_character_filter": {
          "pattern": "[\\p{Alpha}\\p{Digit}]",
          "type": "pattern_replace",
          "replacement": ""
        },
        "blank_filter": {
          "pattern": "[\\p{Blank}]",
          "type": "pattern_replace",
          "replacement": ""
        }
      },
      "tokenizer": { // 2️⃣ 토크나이저
        "korean_nori_tokenizer": {
          "type": "nori_tokenizer",
          "user_dictionary": "user_dic/pat_dic_v3.txt",
          "decompound_mode": "mixed"
        }
      },
      "filter": { // 3️⃣ 토큰 필터
        "nori_posfilter": {
          "type": "nori_part_of_speech",
          "stoptags": ["J","E","NNB","MAJ","MM","XSV","XSA","VCP","SE","XSN","VCN","SP","NA","UNA","VSV","XPN","IC","VV"]
        },
        "ngram2_filter": {
          "type": "edge_ngram",
          "min_gram": 2,
          "max_gram": 20
        }
      },
      "analyzer": { // 4️⃣ 애널라이저
        "nori_analyzer": {
          "type": "custom",
          "tokenizer": "korean_nori_tokenizer",
          "filter" : [
            "lowercase", 
            "nori_posfilter"
          ]
        },
        "ngram_analyzer": {
          "type": "custom",
          "char_filter": [
            "special_character_filter"
          ],
          "tokenizer": "standard",
          "filter" : [
            "ngram2_filter" 
          ]
        },
        "jamo_index_analyzer": {
          "type": "custom",
          "char_filter": [
            "special_character_filter"
          ],
          "tokenizer": "standard",
          "filter": [
            "jamo"
          ]
        },
        "jamo_search_analyzer": {
          "type": "custom",
          "char_filter": [
            "blank_filter",
            "special_character_filter"
          ],
          "tokenizer": "standard",
          "filter": [
            "jamo"
          ]
        },
        "jamo_live_blank_search_analyzer": {
          "type": "custom",
          "char_filter": [
            "special_character_filter"
          ],
          "tokenizer": "standard",
          "filter": [
            "jamo"
          ]
        },
        "number_analyzer" : {
          "type" : "pattern",
          "pattern" :"[.]"
        }
      }
    }
  },
  "mappings": { // 5️⃣ 필드에 데이터 타입 매핑
    "properties": {
      "발명의명칭": {
        "type": "text",
        "analyzer": "jamo_index_analyzer",
        "search_analyzer": "jamo_search_analyzer",
        "fields": {
          "lblank": {
            "type": "text",
            "analyzer": "jamo_index_analyzer",
            "search_analyzer": "jamo_live_blank_search_analyzer"
          },
          "ngram": {
            "type": "text",
            "analyzer": "ngram_analyzer"
          },
          "nori": {
            "type": "text",
            "analyzer": "nori_analyzer"
          }
        }
      },
      "요약": {
        "type": "text",
        "analyzer": "jamo_index_analyzer",
        "search_analyzer": "jamo_search_analyzer",
        "fields": {
          "lblank": {
            "type": "text",
            "analyzer": "jamo_index_analyzer",
            "search_analyzer": "jamo_live_blank_search_analyzer"
          },
          "ngram": {
            "type": "text",
            "analyzer": "ngram_analyzer"
          },
          "nori": {
            "type": "text",
            "analyzer": "nori_analyzer"
          }
        }
      },
      "출원인": {
        "type": "text",
        "analyzer": "jamo_index_analyzer",
        "search_analyzer": "jamo_search_analyzer",
        "fields": {
          "lblank": {
            "type": "text",
            "analyzer": "jamo_index_analyzer",
            "search_analyzer": "jamo_live_blank_search_analyzer"
          },
          "ngram": {
            "type": "text",
            "analyzer": "ngram_analyzer"
          },
          "nori": {
            "type": "text",
            "analyzer": "nori_analyzer"
          }
        }
      },
      "CPC분류": {
        "type": "text"    
      },
      "IPC분류": {
        "type": "text"    
      },
      "event": {
        "properties": {
          "original": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          }
        }
      },
      "log": {
        "properties": {
          "file": {
            "properties": {
              "path": {
                "type": "text",
                "fields": {
                  "keyword": {
                    "type": "keyword",
                    "ignore_above": 256
                  }
                }
              }
            }
          }
        }
      },
      "공개번호": {
        "type": "keyword"      
      },
      "공고번호": {
        "type": "keyword"
      },
      "등록번호": {
       "type": "keyword"
      },
      "법적상태": {
        "type": "keyword" 
      },
      "출원번호": {
        "type": "text",
        "fields": {
          "keyword" : {
            "type" : "keyword",
            "ignore_above": "256"
          }
        } 
      },
      "출원일자": {
        "type": "text",
        "analyzer": "number_analyzer",
        "fields": {
          "keyword" : {
            "type" : "keyword",
            "ignore_above" : 256
          }
        }
      }
    }
  }
}

1. Character Filter

1.1. Pattern Replace Character Filter

정규 표현식을 사용하여 해당 문자들을 특정 문자열로 대체합니다.

pattern replace character filter가 제공하는 옵션은 다음과 같습니다.

  • pattern : 자바 정규 표현식
    표현식의미
    \p{Alpha}문자
    \p{Digit}숫자
    {Blank}space 또는 tab
  • replacement : 대체 문자열
    • special_character_filter: 문자와 숫자를 대체
    • blank_filter: 공백을 대체

2. Tokenizer

2.1. Nori Tokenizer

nori_tokenizer가 제공하는 옵션은 다음과 같습니다.

  • user_dictionary : 사용자 정의 사전 ⇒ v1에서는 특허 검색 서비스에서 사용자 정의 사전을 설정하기 어렵다고 판단하여 배제하였습니다. 하지만 지속적으로 서치한 결과, 한국특허정보원에서 개발한 언어모델을 통해 600만 건의 용어가 있는 사용자 사전을 얻을 수 있었고 v2에는 이를 적용하였습니다.
  • decompound_mode : 복합 명사를 토크나이저가 처리하는 방식을 결정 ⇒ 분리된 복합 명사와 원본 데이터 모두 유지하기 위해 mixed로 설정하였습니다.

3. Token Filter

3.1. nori_part_of_speech

nori_part_of_speech 토큰 필터를 이용해서 제거할 품사(POS - Part Of Speech) 코드입니다.

⇒ “J","E","NNB","MAJ","MM","XSV","XSA","VCP","SE","XSN","VCN","SP","NA","UNA","VSV","XPN","IC","VV"

3.2. edge_ngram

edge-ngram token filter가 제공하는 옵션은 다음과 같습니다.

  • min_gram: 그램의 최소 글자 수
  • max_gram: 그램의 최대 글자 수

4. Analyzer

4.1. nori_analyzer

[발명의명칭], [출원인], [요약] 필드를 멀티 필드로 두고 .nori 필드에 한글 형태소 분석기(Nori)를 적용하였습니다.

4.2. ngram_analyzer

[발명의명칭], [출원인], [요약] 필드를 멀티 필드로 두고 .ngram 필드에 커스텀 애널라이저를 적용하였습니다.

이 커스텀 애널라이저는 캐릭터 필터를 통해 문자, 숫자를 제거하고 standard 토크나이저와 edge n-gram 필터를 사용합니다.

4.3. jamo_index_analyzer

[발명의명칭], [요약], [출원인] 필드를 멀티 필드로 두고 .lblank 필드에 커스텀 애널라이저를 적용하였습니다.

이 커스텀 애널라이저는 캐릭터 필터를 통해 문자, 숫자를 제거하고 standard 토크나이저와 jamo 필터를 사용합니다.

4.4. jamo_search_analyzer

jamo_index_analyzer로 색인된 용어들을 잘 찾기 위해 검색 시에 search analyzer를 적용하였습니다.

이 커스텀 애널라이저는 캐릭터 필터를 통해 문자, 숫자, 공백을 제거하고 standard 토크나이저와 jamo 필터를 사용합니다.

4.5. jamo_live_blank_search_analyzer

jamo_index_analyzer로 색인된 용어들을 잘 찾기 위해 검색 시에 search analyzer를 적용하였습니다.

이 커스텀 애널라이저는 캐릭터 필터를 통해 문자, 숫자를 제거하고 standard 토크나이저와 jamo 필터를 사용합니다.

4.6. number_analyzer

[출원일자] 필드의 데이터는 ‘2022.09.21’의 형태를 가집니다.

그 중에서 연도(2022)만 추출하기 위해 패턴 “[.]”을 기준으로 텍스트를 분리하는 패턴 애널라이저를 적용했습니다.

5. 필드에 데이터 타입 매핑

  • [출원번호] : text, keyword
  • [출원일자] : text, keyword
  • [발명의명칭] : text
  • [출원인] text
  • [IPC분류] text
  • [CPC분류] text
  • [공고번호] keyword
  • [공개번호] keyword
  • [등록번호] keyword
  • [법적상태] keyword
  • [요약] text

개선점

  • v1과 달리, 키워드를 검색하면 원하는 결과를 얻을 수 있었습니다.
    • 검색한 키워드: 오일저장탱크
    • 예상 반환 결과:
    • 실제 반환 결과: 3 hits
      {
        "took": 59,
        "timed_out": false,
        "_shards": {
          "total": 1,
          "successful": 1,
          "skipped": 0,
          "failed": 0
        },
        "hits": {
          "total": {
            "value": 3,
            "relation": "eq"
          },
          "max_score": 26.637434,
          "hits": [
            {
              "_index": "user-dic-plus",
              "_id": "52ulk4MBvrSsT3SDS3_T",
              "_score": 26.637434,
              "_source": {
                "요약": "본 고안은 오일저장탱크를 갖춘 차량용 브레이크의 마스터실린더에 관한 것으로, 그 목적은 오일감지장치의 플로트가 오일저장탱크의 천정면에 접착되는 것을 방지하는 것이다. 본 고안에 따른 오일저장탱크를 갖춘 차량용 브레이크의 마스터실린더는 오일저장탱크(20) 내에 마련되는 플로트(31)의 상면에 다수개의 돌기(33)를 형성하여 오일의 점성 및 표면장력에 의해 탱크(20)의 천정면에 달라붙는 것을 방지하였다. 따라서 플로트(31)는 항상 오일의 액면상에 떠있게 되어 본 기능을 원활하게 수행하며, 이의 전체적인 신뢰성이 향상되는 이점이 있다.",
                "발명의명칭": "오일저장탱크를 갖춘 차량용 브레이크의 마스터실린더()"
              }
            },
            {
              "_index": "user-dic-plus",
              "_id": "SGulk4MBvrSsT3SDioXv",
              "_score": 18.489084,
              "_source": {
                "요약": "본 발명은 용기(1)와, 용기의 상부 일 측에 파이프에 연결 설치되어 오일이 유입되는 오일저장탱크(2)와, 상기 용기(1)의 다른 상부 일 측에 파이프에 연결 설치되며 용기내의 압력을 감압시키는 진공펌프(4)와, 상기 용기(1)의 하부 일 측에 파이프에 연결 설치되어 오존을 용기(1)내에 유입된 오일(7)에 용해시키도록 공급하는 오존발생장치(3)와, 상기 용기(1)내의 하부 다른 일 측에 설치된 배출구(5)와, 용기(1)내의 몸체에 중앙부에 설치된 관찰창(6)과, 용기(1)의 하부에 설치된 진동장치(8)로 구성된 저농도 오존을 함유하는 오일제제 제조장치 및 그 제법. 저농도 오존화 오일제제 제조장치. 저농도 오존화 오일제제 제법. 진공펌프. 오존발생장치. 진동장치.",
                "발명의명칭": "저농도 오존을 함유하는 오일제제 제조장치 및 그 제법(Production method and apparatus for ozonized oil)"
              }
            },
            {
              "_index": "user-dic-plus",
              "_id": "wmukk4MBvrSsT3SDxGpH",
              "_score": 15.39892,
              "_source": {
                "요약": "본 발명은 음식물 쓰레기 처리장치에 관한 것으로서 그 기술적인 수단은, 본체부(1)의 상부 일측면에 쓰레기 투입구(7)가 설치되고, 상기 본체부(1)의 내측에 형성되는 몸체(13)의 저면에 스크류 컨베이어(11) (11´) (11˝)로 이루어진 분쇄수단(14)이 설치되며, 상기 분쇄수단(14)의 상측에 중공의 회전축(15)에 연결되는 다수의 패들(16)로서 구성되는 교반기(17)가 설치되고, 상기 회전축(15)에 다수의 에어홀(34)이 형성한다. 또한, 상기 몸체(13)의 측면 상, 하에 전동기(18) (19)를 각각 설치하여 그 상측의 전동기(18)를 교반기(17)에 체인(22) 연결하고, 상기 하측의 전동기(19)를 스크류 컨베이어(11) 결합되는 스프로킷(23)에 체인(24) 연결하며, 상기 스크류 컨베이어(11)와 그 일측의 스크류 컨베이어(11´)는 기어 (25) (26) 결합되고, 상기 스크류 컨베이어(11)와 그 타측의 스크류 컨베이어(11˝)는 체인(27) 연결되며, 상기 몸체(13)의 외 측면 하부에 오일 저장탱크(29)를 설치하고, 상기 오일저장탱크(29)의 외 측면 저부에 히터장치(30)를 설치하며, 상기 히터장치(30)의 일 측에 송풍기 (31)를 설치하여 회전축(15)에 형성되는 에어 홀(34)에 에어를 공급토록 연결하고, 상기 몸체(13)의 일측에 결로장치(32)를 설치하는 것을 요지로 한다.",
                "발명의명칭": "음식물 쓰레기 처리장치()"
              }
            }
          ]
        }
      }
  • 인덱스텀과 쿼리텀 불일치 문제 해결
    • jamo_search_analyzer는 캐릭터 필터에서 공백을 제거하고, jamo_live_blank_search_analyzer는 캐릭터 필터에서 공백을 제거하지 않았습니다.
    • 두 개의 search_analyzer를 통해 인덱스텀과 쿼리텀이 일치하지 않는 문제를 해결했습니다.
      • jamo_index_analyzer로 만든 인덱스텀
        • ㅇㅗㅇㅣㄹㅈㅓㅈㅏㅇㅌㅐㅇㅋㅡㄹㅡㄹ
      • jamo_search_analyzer로 만든 쿼리텀
        • ㅇㅗㅇㅣㄹㅈㅓㅈㅏㅇㅌㅐㅇㅋㅡㄹㅡㄹㄱㅏㅈㅊㅜㄴㅊㅏㄹㅑㅇㅇㅛㅇㅂㅡㄹㅔㅇㅣㅋㅡㅇㅡㅣㅁㅏㅅㅡㅌㅓㅅㅣㄹㄹㅣㄴㄷㅓ
      • jamo_live_blank_search_analyzer로 만든 쿼리텀
        • ㅇㅗㅇㅣㄹㅈㅓㅈㅏㅇㅌㅐㅇㅋㅡㄹㅡㄹ

문제점

  • 검색 키워드에 오타가 있을 때 검색 결과 정확도가 떨어지는 문제
    • 검색한 키워드: 어일저장탱크
    • 예상 반환 결과:
    • 실제 반환 결과: 예상 반환 데이터 누락
      {
        "took": 8,
        "timed_out": false,
        "_shards": {
          "total": 1,
          "successful": 1,
          "skipped": 0,
          "failed": 0
        },
        "hits": {
          "total": {
            "value": 2,
            "relation": "eq"
          },
          "max_score": 14.601166,
          "hits": [
            {
              "_index": "user-dic-plus",
              "_id": "wmukk4MBvrSsT3SDxGpH",
              "_score": 14.601166,
              "_source": {
                "요약": "본 발명은 음식물 쓰레기 처리장치에 관한 것으로서 그 기술적인 수단은, 본체부(1)의 상부 일측면에 쓰레기 투입구(7)가 설치되고, 상기 본체부(1)의 내측에 형성되는 몸체(13)의 저면에 스크류 컨베이어(11) (11´) (11˝)로 이루어진 분쇄수단(14)이 설치되며, 상기 분쇄수단(14)의 상측에 중공의 회전축(15)에 연결되는 다수의 패들(16)로서 구성되는 교반기(17)가 설치되고, 상기 회전축(15)에 다수의 에어홀(34)이 형성한다. 또한, 상기 몸체(13)의 측면 상, 하에 전동기(18) (19)를 각각 설치하여 그 상측의 전동기(18)를 교반기(17)에 체인(22) 연결하고, 상기 하측의 전동기(19)를 스크류 컨베이어(11) 결합되는 스프로킷(23)에 체인(24) 연결하며, 상기 스크류 컨베이어(11)와 그 일측의 스크류 컨베이어(11´)는 기어 (25) (26) 결합되고, 상기 스크류 컨베이어(11)와 그 타측의 스크류 컨베이어(11˝)는 체인(27) 연결되며, 상기 몸체(13)의 외 측면 하부에 오일 저장탱크(29)를 설치하고, 상기 오일저장탱크(29)의 외 측면 저부에 히터장치(30)를 설치하며, 상기 히터장치(30)의 일 측에 송풍기 (31)를 설치하여 회전축(15)에 형성되는 에어 홀(34)에 에어를 공급토록 연결하고, 상기 몸체(13)의 일측에 결로장치(32)를 설치하는 것을 요지로 한다.",
                "발명의명칭": "음식물 쓰레기 처리장치()"
              }
            },
            {
              "_index": "user-dic-plus",
              "_id": "SGulk4MBvrSsT3SDioXv",
              "_score": 14.172298,
              "_source": {
                "요약": "본 발명은 용기(1)와, 용기의 상부 일 측에 파이프에 연결 설치되어 오일이 유입되는 오일저장탱크(2)와, 상기 용기(1)의 다른 상부 일 측에 파이프에 연결 설치되며 용기내의 압력을 감압시키는 진공펌프(4)와, 상기 용기(1)의 하부 일 측에 파이프에 연결 설치되어 오존을 용기(1)내에 유입된 오일(7)에 용해시키도록 공급하는 오존발생장치(3)와, 상기 용기(1)내의 하부 다른 일 측에 설치된 배출구(5)와, 용기(1)내의 몸체에 중앙부에 설치된 관찰창(6)과, 용기(1)의 하부에 설치된 진동장치(8)로 구성된 저농도 오존을 함유하는 오일제제 제조장치 및 그 제법. 저농도 오존화 오일제제 제조장치. 저농도 오존화 오일제제 제법. 진공펌프. 오존발생장치. 진동장치.",
                "발명의명칭": "저농도 오존을 함유하는 오일제제 제조장치 및 그 제법(Production method and apparatus for ozonized oil)"
              }
            }
          ]
        }
      }
    • 검색 결과가 없는 이유: 쿼리텀에 일치하는 인덱스텀이 존재하지 않음
      • nori_analyzer
        • 인덱스텀: 오일저장탱크 차량 브레이크 마스터실린더
        • 쿼리텀: 저장탱크
      • ngram_analyzer
        • 인덱스텀: 오일 오일저 오일저장 오일저장탱 오일저장탱크 오일저장탱크를
        • 쿼리텀: 어일 어일저 어일저장 어일저장탱 어일저장탱크
      • jamo_index_analyzer로 만든 인덱스텀
        • ㅇㅗㅇㅣㄹㅈㅓㅈㅏㅇㅌㅐㅇㅋㅡㄹㅡㄹ ㄱㅏㅈㅊㅜㄴ ㅊㅏㄹㅑㅇㅇㅛㅇ
      • jamo_search_analyzer로 만든 쿼리텀
        • ㅇㅓㅇㅣㄹㅈㅓㅈㅏㅇㅌㅐㅇㅋㅡ
      • jamo_live_blank_search_analyzer로 만든 쿼리텀
        • ㅇㅓㅇㅣㄹㅈㅓㅈㅏㅇㅌㅐㅇㅋㅡ

해결 방법 및 대안

  • Edge n-gram 애널라이저를 Ngram 애널라이저로 변경 시도
    • Edge n-gram은 키워드의 시작부터 min_gram과 max_gram 옵션에 따라 토큰을 나누기 때문에 단어의 맨 앞 글자부터 오타가 있으면 원하는 검색 결과를 얻을 수 없었습니다.
    • 쿼리텀과 일치하는 부분을 많이 생성하고자 Edge n-gram 애널라이저를 Ngram 애널라이저로 변경하기로 결정하였습니다.
profile
정성과 진심을 담아 흔적을 기록하자💡

3개의 댓글

comment-user-thumbnail
2024년 5월 18일

안녕하세요 설명이 너무 잘 작성되어서 도움이 많이 됐습니다.
한 가지 질문 드릴 내용이 있는데 jamo 필터는 elasticsearch에 없는 필터링인데 혹시 출처나 사용하셨던 분석기 파일을 받을 수 있을까요?

1개의 답글