반응형
반응형
#/**───────────────────────────────────────────────────────────
#
#                  오타교정어
#
#───────────────────────────────────────────────────────────*/


# ─── 오타교정어 생성
PUT typo_correction
{
  "mappings":{
    "properties":{
        "right_word":{
          "type" : "keyword"
        },
       "wrong_words":{
          "type":"nested",
          "properties":{
             "wrong_words":{
                "type":"keyword"
             }
          }
       }
    }
  }
}

# ─── 오타교정어 단건 INSERT
PUT typo_correction/_bulk
{"index" : {}}
{"right_word":"짜장","wrong_words":{"wrong_words":["쨔장","차장"]}}


# ─── 오타교정어 검색
GET typo_correction/_search
{
  "query": {
    "nested": {
      "path": "wrong_words",
      "query": {
        "bool": {
          "must": [
            {
              "match": {
                "wrong_words.wrong_words": "참봉"
              }
            }
          ]
        }
      }
    }
  },"size":1
}

# ─── 조회된 레코드 삭제
POST typo_correction/_delete_by_query
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "right_word": "짬뽕"
          }
        }
      ]
    }
  }
}

# ─── 오타교정어 삭제
DELETE typo_correction


#/**───────────────────────────────────────────────────────────
#
#                  인기검색어
#
#───────────────────────────────────────────────────────────*/

# ─── 인기검색어 생성
PUT popular
{
   "mappings":{
      "properties":{
         "date":{
            "type":"integer"
         },
         "index":{
            "type":"keyword"
         },
         "keyword":{
            "type":"keyword"
         },
         "search_time":{
            "type":"integer"
         },
         "time":{
            "type":"long"
         }
      }
   }
}

# ─── 인기검색어 단건 INSERT
PUT popular/_bulk
{"index" : {}}
{"keyword" : "코스프레", "index" : "covid", "date" :20230402 , "search_time" : 141130 , "time" : 20230402141130}



# ─── 시간 인기검색어 조회
GET popular/_search
{
   "query":{
      "bool":{
         "must":[
            {
               "bool":{
                  "should":[
                     {
                        "match":{
                           "keyword":"코스프레"
                        }
                     }
                  ]
               }
            },
            {
               "bool":{
                  "filter":[
                     {
                        "range":{
                           "time":{
                              "lte":"20230402141130"
                           }
                        }
                     },
                     {
                        "range":{
                           "time":{
                              "gte":"20230402133056"
                           }
                        }
                     }
                  ]
               }
            },
            {
               "bool":{
                  "should":[
                     {
                        "match":{
                           "index":"covid"
                        }
                     }
                  ]
               }
            }
         ]
      }
   },
   "size":10,
   "aggs":{
      "keyword":{
         "terms":{
            "field":"keyword"
         }
      }
   }
}


# ─── 날짜 인기검색어 조회
GET popular/_search
{
  "query":{
    "bool": {
      "filter": [ 
        { "range": { "date": { "gte": "20211220" }}}
      ]
    }
  },
  "size": 0,
  "aggs": {
    "keyword": {
      "terms": {
        "field": "keyword"
      }
    }
  }
}



# ─── 조회된 레코드 삭제
POST popular/_delete_by_query
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "keyword": "종식"
          }
        },
        {
          "match": {
            "index": "covid"
          }
        }
      ]
    }
  }
}

# ─── 인기검색어 삭제
DELETE popular


#/**───────────────────────────────────────────────────────────
#
#                  자동완성어
#
#───────────────────────────────────────────────────────────*/


# ─── 자동완성어 생성
PUT auto_keyword
{
   "mappings":{
      "properties":{
         "auto_keyword":{
            "type":"keyword"
         },
         "count":{
            "type":"integer"
         }
      }
   }
}

# ─── 자동완성어 단건 INSERT
PUT auto_keyword/_bulk
{"index" : {}}
{"auto_keyword" : "금칙어"}


# ─── 자동완성어 조회
GET auto_keyword/_search
{
  "query": {
    "prefix": {
      "auto_keyword": {
        "value": "코로나"
      }
    }
  },
  "collapse":{"field":"auto_keyword"},
   "sort" : [
      { "count": "desc" }
  ]
}


# ─── 조회된 레코드 삭제
POST auto_keyword/_delete_by_query
{
  "query": {
    "match": {
      "auto_keyword": "코로나도"
    }
  }
}

# ─── 자동완성어 삭제
DELETE auto_keyword




#/**───────────────────────────────────────────────────────────
#
#                  금칙어
#
#───────────────────────────────────────────────────────────*/

# ─── 금칙어 생성
PUT forbidden
{
   "mappings":{
      "properties":{
         "forbidden_word":{
            "type":"keyword"
         }
      }
   }
}

# ─── 금칙어 단건 INSERT
PUT forbidden/_bulk
{"index" : {}}
{"forbidden_word" : "금칙어"}


# ─── 금칙어 조회
GET forbidden/_search
{
  "query": {
    "term": {
      "forbidden": {
        "value": "금칙어"
      }
    }
  }
}


# ─── 조회된 레코드 삭제
POST forbidden/_delete_by_query
{
  "query": {
    "match": {
      "forbidden_word": "코로나도"
    }
  }
}

# ─── 금칙어 조회
DELETE forbidden


#/**───────────────────────────────────────────────────────────
#
#                  기본 사전 고도화 분석
#
#───────────────────────────────────────────────────────────*/
PUT normal_dictionary_analyzer
{
   "settings":{
      "analysis":{
         "tokenizer":{
            "korean_nori_tokenizer":{
               "type":"nori_tokenizer",
               "decompound_mode":"none"
            }
         },
         "analyzer":{
            "nori_analyzer":{
               "tokenizer":"korean_nori_tokenizer",
               "filter":[
                 "nori_posfilter"
               ]
            }
         },
         "filter":{
            "nori_posfilter":{
               "type":"nori_part_of_speech",
               "stoptags":[
                  "J",
                  "SP", "SSO", "SSC", "SH", "SF", "SE", "SC", "SY"
                ]
            }
          }
      }
   }
}



# ─── 기본 사전 고도화 분석기 재기동(신조어 즉시 적용)
POST normal_dictionary_analyzer/_close
POST normal_dictionary_analyzer/_open

# ─── 기본 사전 고도화 분석기 삭제
DELETE normal_dictionary_analyzer

# ─── 기본 사전 고도화 분석기 정보 조회
GET normal_dictionary_analyzer/_settings

# ─── 기본 사전 고도화 분석기 문장 상세 분석
GET normal_dictionary_analyzer/_analyze
{
  "analyzer": "nori_analyzer",
  "text":"고소득자",
  "attributes": ["leftPOS", "rightPOS"], 
  "explain": true
}

# ─── 기본 사전 고도화 분석기 문장 분석
GET normal_dictionary_analyzer/_analyze
{
  "analyzer": "nori_analyzer", 
  "text": ""
}



#/**───────────────────────────────────────────────────────────
#
#                  기본 인덱스 생성
#
#───────────────────────────────────────────────────────────*/

# ─── 인덱스 재기동(신조어 즉시 적용)
POST sample/_close
POST sample/_open

# ─── 인덱스 정보 조회
GET sample/_settings

# ─── 분석기 삭제
DELETE sample

# ─── 일반 인덱스 / 분석기 생성 [기본 분석기]
PUT sample
{
   "settings":{
      "analysis":{
         "tokenizer":{
            "korean_nori_tokenizer":{
               "type":"nori_tokenizer",
               "decompound_mode":"none",
               "user_dictionary":"dictionary/newly_coined_word/user_dictionary.txt"
            }
         },
         "analyzer":{
            "nori_analyzer":{
               "tokenizer":"korean_nori_tokenizer",
               "filter":[
                 "nori_posfilter"
               ]
            }
         },
         "filter":{
            "nori_posfilter":{
               "type":"nori_part_of_speech",
               "stoptags":[
                  "J",
                  "SP", "SSO", "SSC", "SH", "SF", "SE", "SC", "SY"
                ]
            }
          }
      }
   }
}

# ─── 분석기 문장 상세 분석
GET sample/_analyze
{
  "analyzer": "nori_analyzer",
  "text":"사용한다",
  "explain": true
}

# ─── 분석기 문장 분석
GET sample/_analyze
{
  "analyzer": "nori_analyzer", 
  "text":"사용한다"
}


#/**───────────────────────────────────────────────────────────
#
#                  인덱스 정보
#
#───────────────────────────────────────────────────────────*/

# ─── 형태소 분석기
GET covid/_analyze
{
  "analyzer": "nori_analyzer", 
  "text":"재발견",
  "explain": true
}

# ─── 스코어 확인하기
PUT score/_doc/1
{
  "contents": "대구·경북 폭염특보…폭염 종합 대책 실시 [KBS 대구] .. ..[앵커] .. .. 오늘 절기상 가장 덥다는 대서인데요, .. .. 연일 무더운 날씨가 이어지면서 대구.경북에도 보름째 폭염특보가 이어지고 있습니다. .. .. 취재기자 연결합니다. .. .. 윤희정 기자,.. 대구시는 코로나 상황을 감안해 실내 무더위 쉼터 대신 강변이나 공원 등에 실외 무더위 쉼터 4백여 곳을 조성했습니다. .."
}



#/**───────────────────────────────────────────────────────────
#
#                  검색 옵션
#
#───────────────────────────────────────────────────────────*/


# ─── 특정 필드만 출력 DSL (title 필드, company 필드만 노출)
# ─── select=title,company
GET covid/_search
{
  "fields": [
    "title",
    "company"
  ],
  "_source": false
}

# ─── 10000건 이상의 결과를 주기 위한 옵션
GET auto_keyword/_search
{
  "track_total_hits": true
}



# ─── offset 및 limit 
# ─── 시작 인덱스 위치 및 보여줄 개수 제한 (0번째 인덱스로부터 30개 보여주기)
# ─── offset=0&limit=30
GET covid/_search
{
  "from" : 0,
  "size" : 30
}



#/**───────────────────────────────────────────────────────────
#
#                  검색
#
#───────────────────────────────────────────────────────────*/


# ─── anyword
# ─── 키워드 or 조건절 (마스크가 있거나 덴탈이 있어야한다.)
# ─── contents = "마스크 덴탈" anyword
GET covid/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "contents": "마스크 덴탈"
          }
        }
      ]
    }
  }
}

# ─── allword
# ─── 키워드 and 조건절 (마스크도 있고 덴탈도 있어야한다.)
# ─── contents = "마스크 덴탈" allword
GET search/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "contents": {
              "query" : "그린",
              "operator" : "and"
            }
          }
        }
      ]
    }
  }
}

# ─── and
# ─── 같은 키워드 and 조건절 (contents의 코로나가 포함되면서 title의 코로나가 포함) 
#     [두개 필드에 키워드가 둘다 존재해야 함]
# ─── contenst = '코로나' and title = '코로나'
GET covid/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "contents": "코로나"
          }
        },
        {
          "match": {
            "title": "코로나"
          }
        }
      ]
    }
  }
}

# ─── 멀티 필드 allword
# ─── 키워드 and 조건절 (contents에 폭염과 더위가 있어야하거나 + title에 폭염과 더위가 있어야한다.)
# ─── contents,title = '폭염 더위' allword
GET covid/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "multi_match": {
            "query": "폭염 더위",
            "fields": ["contents", "title"],
            "operator": "and"
          }
        }
      ]
    }
  }
}

# ─── 멀티 필드 anyword
# ─── 키워드 or 조건절 
#     (contents에 폭염 또는 더위가 있어야하거나 + title에 폭염 또는 더위가 있어야한다.) 
#     [두개 필드에 키워드가 둘다 존재해야 함] 
# ─── contents, title = '폭염 더위' anyword
GET covid/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "multi_match": {
            "query": "폭염 더위",
            "fields": ["contents", "title"]
          }
        }
      ]
    }
  },
    "highlight":{
    "pre_tags":["<em>"],
    "post_tags":["</em>"],
    "fields":{
        "contents":{},
        "title" : {}
    }
  }
}

# ─── 멀티 필드 anyword와 다른점 = (멀티 필드 anyword는 contents 또는 title 중에서 스코어가 높은게 위로가지만 or절로 묶은 건 스코어를 합산한다.)
# ─── contents, title = '폭염 더위' anyword   
#       vs  
#     (contents = '폭염 더위' anyword) or (title = '폭염 더위')
GET covid/_search
{
  "size" : 80,
  "query": {
    "bool": {
      "should": [
        {
          "multi_match": {
            "query": "폭염 더위",
            "fields": ["contents"]
          }
        },
        {
          "multi_match": {
            "query": "폭염 더위",
            "fields": ["title"]
          }
        }
      ]
    }
  }
}


# ─── (contents, title = "코로나" allword and wirter="윤희정" anyword) 
#      or 
#     (contents, title = "코로나" allword and writer = "박종일" anyword)
GET covid/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "bool": {
            "must": [
             {
                "multi_match": {
                  "query": "코로나",
                  "fields": ["contents", "title"],
                  "operator": "and"
                }
              },
              {
                "multi_match": {
                  "query": "윤희정",
                  "fields": ["writer"]
                }
              }
            ]
          }
        },
        {
          "bool": {
            "must": [
             {
                "multi_match": {
                  "query": "코로나",
                  "fields": ["contents", "title"],
                  "operator": "and"
                }
              },
              {
                "multi_match": {
                  "query": "박종일",
                  "fields": ["writer"]
                }
              }
            ]
          }
        }
      ]
    }
  }
}


# ─── (contents, title = "코로나" allword and wirter="박종일" anyword) 
#      and 
#     (contents, title = "코로나" allword and company != "KBS")
GET covid/_search
{
  "query": {
    "bool": {
      "filter": [ 
        { "range": { "reg_date": { "gte": "20221220" }}}
      ],
      "must": [
        {
          "bool": {
            "must": [
             {
                "multi_match": {
                  "query": "코로나",
                  "fields": ["contents", "title"],
                  "operator": "and"
                }
              },
              {
                "multi_match": {
                  "query": "박종일",
                  "fields": ["writer"]
                }
              }
            ]
          }
        },
        {
          "bool": {
            "must": [
             {
                "multi_match": {
                  "query": "코로나",
                  "fields": ["contents", "title"],
                  "operator": "and"
                }
              }
            ],
            "must_not": [
              {
                "multi_match": {
                  "query": "KBS",
                  "fields": ["company"]
                }
              }
            ]
          }
        }
      ]
    }
  }
}




#/**───────────────────────────────────────────────────────────
#
#                  구간 조회
#
#───────────────────────────────────────────────────────────*/


# ─── range = reg_date > 20221226
GET covid/_search
{
  "query": {
    "bool": {
      "filter": [ 
        { "range": { "reg_date": { "lte": "20221226" }}}
      ]
    }
  }
}

# ─── 멀티 필드 allword  + 날짜 조회 
#     (날짜는 무조건 구간이여야한다   <--- |    | ---->  이딴식 불가능)
# ─── 키워드 and 조건절 
#     (contents에 폭염과 더위가 있어야하거나 title에 폭염과 더위가 있어야한다.)
# ─── contents, title = "폭염 더위" allword & range = reg_date > 20221226
GET covid/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "multi_match": {
            "query": "폭염 더위",
            "fields": ["contents", "title"],
            "operator": "and"
          }
        }
      ],
      "filter": [ 
        { "range": { "reg_date": { "gte": "20221206" }}},
        { "range": { "reg_date": { "lte": "20221222" }}}
      ]
    }
  }
}


#/**───────────────────────────────────────────────────────────
#
#                  정렬 (type이 integer여야한다)
#
#───────────────────────────────────────────────────────────*/

# ─── order = reg_date asc
GET covid/_search
{
 "sort" : [
      { "reg_date": "asc" }
  ]
}


# ─── order = reg_date asc
GET covid/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "multi_match": {
            "query": "폭염 더위",
            "fields": ["contents", "title"],
            "operator": "and"
          }
        }
      ]
    }
  },
   "sort" : [
      { "reg_date": "asc" }
  ]
}


#/**───────────────────────────────────────────────────────────
#
#                  하이라이팅
#
#───────────────────────────────────────────────────────────*/

# ─── highlight-start=<em>&highlight-end=</em>&highlight-fields=contents
GET covid/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "contents": "마스크 덴탈"
          }
        }
      ]
    }
  },
  "highlight":{
    "pre_tags":["<em>"],
    "post_tags":["</em>"],
    "fields":{
        "contents":{}
    }
  }
}
──── 검색엔진 셋팅 ────
1. sudo vi /etc/security/limits.conf 

2. 하기 내용 추가
my_search soft memlock unlimited
my_search soft fsize unlimited
my_search hard nofile 65536
my_search soft nofile 65536
my_search hard nproc 65536
my_search soft nproc 65536

3. sudo vi /etc/sysctl.conf 

4. 하기 내용 추가
vm.max_map_count=262144

─── fargate 적용 시 셋팅 값
1. vi ${설치경로}/es/elastic/config/elasticsearch.yml 

2. 하기 내용 추가
node.store.allow_mmap: false
transport.host: localhost
transport.tcp.port: 9300


─── 검색엔진 Dockerfile 내용 ───
FROM company/my_search:1.1

USER search

EXPOSE 9200
EXPOSE 8021

WORKDIR /home

CMD ./start.sh
───────────────────
─── start.sh 내용 ───

${설치경로}/service/bin/startup.sh
${설치경로}/es/elastic/bin/elasticsearch

───────────────────

 

 

참고자료

반응형
반응형

 

엘라스틱은 외국에서 만들어졌기 때문에 영어기반의 형태소 분석기가 기본입니다.

한국어에는 다양한 품사와 활용어 등이 있기 때문에 그에 맞는 형태소 분석기가 필요합니다.

 

여러가지가 있지만 엘라스틱에서 정식적으로 채용한 형태소 분석기는 노리형태소 분석기입니다.

 

설치 방법은 엘라스틱 메뉴얼을 참조하시길 바랍니다.

 

https://esbook.kimjmin.net/06-text-analysis/6.7-stemming/6.7.2-nori

 

6.7.2 노리 (nori) 한글 형태소 분석기 - Elastic 가이드북

커뮤니티 한글 형태소 분석기 - 아리랑, 은전한닢, Open Korean Text

esbook.kimjmin.net

 

📝노리형태소 분석기 생성

PUT my_nori
{
  "settings": {
    "analysis": {
      "tokenizer": {
        "nori_none": {
          "type": "nori_tokenizer",
          "decompound_mode": "none"
        },
        "nori_discard": {
          "type": "nori_tokenizer",
          "decompound_mode": "discard"
        },
        "nori_mixed": {
          "type": "nori_tokenizer",
          "decompound_mode": "mixed"
        }
      }
    }
  }
}

 

노리형태소 분석기에는 다양한 분해 단계가 있습니다.

 

  1. none
    • 합성어만 저장합니다
  2. discard
    • 합성어를 분리해 각 어근(의미있는 단어)만 저장합니다
  3. mixed
    • 어근과 합성어 모두 저장합니다. (none + mixed)

 

📝노리형태소 분석기 테스트 (형태소 분석기) [ none ]

# none

GET my_nori/_analyze
{
  "tokenizer": "nori_none",
  "text": [ "백두산이" ]
}

# --- result ---

{
  "tokens" : [
    {
      "token" : "백두산",
      "start_offset" : 0,
      "end_offset" : 3,
      "type" : "word",
      "position" : 0
    },
    {
      "token" : "이",
      "start_offset" : 3,
      "end_offset" : 4,
      "type" : "word",
      "position" : 1
    }
  ]
}​

 

📝노리형태소 분석기 테스트 (형태소 분석기) [ discard ] 

# discard

GET my_nori/_analyze
{
  "tokenizer": "nori_discard",
  "text": [ "백두산이" ]
}

# --- result ---

{
  "tokens" : [
    {
      "token" : "백두",
      "start_offset" : 0,
      "end_offset" : 2,
      "type" : "word",
      "position" : 0
    },
    {
      "token" : "산",
      "start_offset" : 2,
      "end_offset" : 3,
      "type" : "word",
      "position" : 1
    },
    {
      "token" : "이",
      "start_offset" : 3,
      "end_offset" : 4,
      "type" : "word",
      "position" : 2
    }
  ]
}​

 

📝노리형태소 분석기 테스트 (형태소 분석기) [ mixed ] 

# mixed

GET my_nori/_analyze
{
  "tokenizer": "nori_mixed",
  "text": [ "백두산이" ]
}


# --- result ---

{
  "tokens" : [
    {
      "token" : "백두산",
      "start_offset" : 0,
      "end_offset" : 3,
      "type" : "word",
      "position" : 0,
      "positionLength" : 2
    },
    {
      "token" : "백두",
      "start_offset" : 0,
      "end_offset" : 2,
      "type" : "word",
      "position" : 0
    },
    {
      "token" : "산",
      "start_offset" : 2,
      "end_offset" : 3,
      "type" : "word",
      "position" : 1
    },
    {
      "token" : "이",
      "start_offset" : 3,
      "end_offset" : 4,
      "type" : "word",
      "position" : 2
    }
  ]
}
 
 
 
 
 

 

  • 이러한 기준으로 품사 분해되어 저장됩니다 이걸 이용해 필요 없는 품사를 없앨 수 있습니다
  • 예를 들어 IC 감탄사 "아!" 이런 부분은 검색에 의미가 없죠

 

📝불용어 (stopwords)

PUT my_pos
{
  "settings": {
    "index": {
      "analysis": {
        "filter": {
          "my_pos_f": {
            "type": "nori_part_of_speech",
            "stoptags": [
              "NR"
            ]
          }
        }
      }
    }
  }
}

 

이런식으로 필터를 추가해 분석기 튜닝이 가능합니다.

 

📝상세 형태소 분석 

GET _analyze
{
  "tokenizer": "nori_tokenizer",
  "text": "동해물과 백두산이",
  "explain": true
}

# --- result ---

{
  "detail" : {
    "custom_analyzer" : true,
    "charfilters" : [ ],
    "tokenizer" : {
      "name" : "nori_tokenizer",
      "tokens" : [
        {
          "token" : "동해",
          "start_offset" : 0,
          "end_offset" : 2,
          "type" : "word",
          "position" : 0,
          "bytes" : "[eb 8f 99 ed 95 b4]",
          "leftPOS" : "NNP(Proper Noun)",
          "morphemes" : null,
          "posType" : "MORPHEME",
          "positionLength" : 1,
          "reading" : null,
          "rightPOS" : "NNP(Proper Noun)",
          "termFrequency" : 1
        },
        {
          "token" : "물",
          "start_offset" : 2,
          "end_offset" : 3,
          "type" : "word",
          "position" : 1,
          "bytes" : "[eb ac bc]",
          "leftPOS" : "NNG(General Noun)",
          "morphemes" : null,
          "posType" : "MORPHEME",
          "positionLength" : 1,
          "reading" : null,
          "rightPOS" : "NNG(General Noun)",
          "termFrequency" : 1
        },
        {
          "token" : "과",
          "start_offset" : 3,
          "end_offset" : 4,
          "type" : "word",
          "position" : 2,
          "bytes" : "[ea b3 bc]",
          "leftPOS" : "J(Ending Particle)",
          "morphemes" : null,
          "posType" : "MORPHEME",
          "positionLength" : 1,
          "reading" : null,
          "rightPOS" : "J(Ending Particle)",
          "termFrequency" : 1
        },
        {
          "token" : "백두",
          "start_offset" : 5,
          "end_offset" : 7,
          "type" : "word",
          "position" : 3,
          "bytes" : "[eb b0 b1 eb 91 90]",
          "leftPOS" : "NNG(General Noun)",
          "morphemes" : null,
          "posType" : "MORPHEME",
          "positionLength" : 1,
          "reading" : null,
          "rightPOS" : "NNG(General Noun)",
          "termFrequency" : 1
        },
        {
          "token" : "산",
          "start_offset" : 7,
          "end_offset" : 8,
          "type" : "word",
          "position" : 4,
          "bytes" : "[ec 82 b0]",
          "leftPOS" : "NNG(General Noun)",
          "morphemes" : null,
          "posType" : "MORPHEME",
          "positionLength" : 1,
          "reading" : null,
          "rightPOS" : "NNG(General Noun)",
          "termFrequency" : 1
        },
        {
          "token" : "이",
          "start_offset" : 8,
          "end_offset" : 9,
          "type" : "word",
          "position" : 5,
          "bytes" : "[ec 9d b4]",
          "leftPOS" : "J(Ending Particle)",
          "morphemes" : null,
          "posType" : "MORPHEME",
          "positionLength" : 1,
          "reading" : null,
          "rightPOS" : "J(Ending Particle)",
          "termFrequency" : 1
        }
      ]
    },
    "tokenfilters" : [ ]
  }
}

 

형태소 분석기는 검색에 지대한 영향을 끼치기 때문에 어떤식으로 분해되고 어떤 품사인지에 대해서 알려주는 옵션도 있습니다.

 

📝사용자 사전 (user_dictionary)

PUT my_nori
{
  "settings": {
    "analysis": {
      "tokenizer": {
        "my_nori_tokenizer": {
          "type": "nori_tokenizer",
	  "user_dictionary" : "dictionary/newly_coined_word/newly_coined_word_sungjaefileinc.txt"
        }
      }
    }
  }
}

 

노리 형태소 분석기가 원하는대로 분석이 안 되는 경우 사용자 사전을 추가하여 원하는 방향으로 유도할 수 있습니다.

배열로 하나씩 넣어줄 수 있지만 관리하기도 어려워지고 지저분해지기 때문에 텍스트 파일 즉 사용자 사전을 따로 만들어 관리해주는게 좋습니다.

 

${엘라스틱 설치 위치}/config/기본 root directory 입니다.

 

 

📝불용어 사전 (stopwords)

{
   "settings":{
      "analysis":{
         "filter":{
            "my_stop_filter":{
               "type":"stop",
               "stopwords_path":"dictionary/stopword/stopword_menu.txt"
            }
         },
         "analyzer":{
            "nori_analyzer":{
               "filter":[
                  "my_stop_filter"
               ],
               "tokenizer":"korean_nori_tokenizer"
            }
         },
         "tokenizer":{
            "korean_nori_tokenizer":{
               "type":"nori_tokenizer",
               "user_dictionary":"dictionary/newly_coined_word/newly_coined_word_menu.txt",
               "decompound_mode":"none"
            }
         }
      }
   }
}

 

📝동의어 사전 (synonym)

{
   "settings":{
      "analysis":{
         "filter":{
            "my_synonym":{
               "type":"synonym_graph",
               "synonyms_path":"dictionary/synonym/synonym_menu.txt",
               "lenient":"true"
            }
         },
         "analyzer":{
            "nori_analyzer":{
               "filter":[
                  "my_synonym"
               ],
               "tokenizer":"korean_nori_tokenizer"
            }
         },
         "tokenizer":{
            "korean_nori_tokenizer":{
               "type":"nori_tokenizer",
               "user_dictionary":"dictionary/newly_coined_word/newly_coined_word_menu.txt",
               "decompound_mode":"none"
            }
         }
      }
   }
}

 

type이 synonym_graph인 경우 인덱스를 close 및 open시 즉시 적용이 된다.

 

📝open, close

POST my_nori/_close
POST my_nori/_open

인덱스를 닫을 경우 검색이 안되며 오픈을 해야 검색이 가능하다. (close 후 open시 사용자 사전[신조어] 및 동의어가 바로 적용이 된다) 

반응형
반응형

📝인덱스 삭제

DELETE board
# board 인덱스 삭제

 

📝레코드 추가

POST board/_doc/1 
{
  "title" : "한국항공우주산업 너무 재미있어요."
}
# board 인덱스 1번 레코드의 title필드에 값 추가

 

📝인덱스 레코드 조회

GET board/_search
{
  "query": {
    "match": {
      "title": {
        "query": "한국"
      }
    }
  }
}
# board 인덱스에 title 필드에 "한국" 포함되는 조건 조회

 

📝분석기를 이용한 텍스트 형태소 분석 결과 조회

GET board/_analyze
{
  "analyzer": "nori",
  "text": "한국항공우주산업"  
}
# board 인덱스에 nori 분석기를 사용한 형태소 분해 결과 조회 (여기서 nori는 노리형태소분석기)
# 형태소 분해 결과와 일치하는 단어로 검색해야 검색에 노출된다.

GET board/_analyze
{
  "analyzer": "nori",
  "text": "한국항공우주산업",
  "explain": true
}
# explain : nori 분석기를 이용해서 나오는 모든 형태소 분해 결과를 상세히 보여준다 (품사 종류 등...)
# stoptags filter 적용이 안 된 상태로 다 보여준다.

 

📝인덱스 생성

PUT board
{
  "mappings" : {
    "properties" : {
      "category" : {
        "type" : "text"
      },
      "company" : {
        "type" : "text"
      },
      "contents" : {
        "type" : "text",
        "analyzer": "nori"
      },
      "del_yn" : {
        "type" : "text"
      },
      "file_path" : {
        "type" : "text"
      },
      "file_contents" : {
        "type" : "text"
      },
      "id" : {
        "type" : "integer"
      },
      "modi_date" : {
        "type" : "date"
      },
      "reg_date" : {
        "type" : "text"
      },
      "title" : {
        "type" : "text"
      },
      "writer" : {
        "type" : "text"
      }
    }
  },
  "settings" : {
    "index" : {
      "analysis" : {
        "filter" : {
          "nori_posfilter" : {
            "type" : "nori_part_of_speech",
            "stoptags" : [
              "J",
              "SP",
              "VSV",
              "UNKNOWN",
              "UNA",
              "SSO",
              "SSC",
              "SP",
              "SH",
              "SF",
              "SE",
              "SC",
              "NA",
              "E",
              "NNB",
              "XSV",
              "VV",
              "XSA",
              "VA",
              "VX",
              "VCP"
            ]
          }
        },
        "analyzer" : {
          "nori" : {
            "filter" : [
              "nori_posfilter"
            ],
            "tokenizer" : "korean_nori_tokenizer"
          }
        },
        "tokenizer" : {
          "korean_nori_tokenizer" : {
            "type" : "nori_tokenizer",
            "decompound_level" : "mixed",
            "user_dictionary" : "dictionary/newly_coined_word/newly_coined_word_sungjaefileinc.txt"
          }
        }
      }
    }
  }
}

|―mapping

|settings

        |index

        |analysis

                  |filter

                  | analyzer

                  | tokenizer

 

📝매핑

"mappings" : {
"properties" : {
  "category" : {
    "type" : "text"
  },
  "company" : {
    "type" : "text"
  },
  "contents" : {
    "type" : "text",
    "analyzer": "nori"
  },
  "del_yn" : {
    "type" : "text"
  },
  "file_path" : {
    "type" : "text"
  },
  "file_contents" : {
    "type" : "text"
  },
  "id" : {
    "type" : "integer"
  },
  "modi_date" : {
    "type" : "date"
  },
  "reg_date" : {
    "type" : "text"
  },
  "title" : {
    "type" : "text"
  },
  "writer" : {
    "type" : "text"
  }
}

# 키 이름은 category 이고 type은 text (전문)이다.
# ....
# 키 이름은 id 이고 type 은 integer(정수)이다.

 

📝필터

"filter" : {
  "nori_posfilter" : {
    "type" : "nori_part_of_speech",
    "stoptags" : [
      "J",
      "SP",
      "VSV",
      "UNKNOWN",
      "UNA",
      "SSO",
      "SSC",
      "SP",
      "SH",
      "SF",
      "SE",
      "SC",
      "NA",
      "E",
      "NNB",
      "XSV",
      "VV",
      "XSA",
      "VA",
      "VX",
      "VCP"
    ]
  }
}
# nori_posfilter는 filter 이름
# nori_part_of_speech은 nori에서 제공하는 필터로 품사에 대한 제외어(불용어)처리가 가능하다

 

📝분석기

"analyzer" : {
  "nori" : {
    "filter" : [
      "nori_posfilter"
    ],
    "tokenizer" : "korean_nori_tokenizer"
  }
}
# analyzer는 형태소 분석기를 선언한다.
# nori라는 이름이고 filter는 위에 설명한 nori_posfilter를 이용한다.
# tokenizer로는 korean_nori_tokenizer 이름의 분석기를 사용한다 (여기에선 노리형태소분석기)

 

📝형태소 분석기

"tokenizer" : {
  "korean_nori_tokenizer" : {
    "type" : "nori_tokenizer",
    "decompound_level" : "mixed",
    "user_dictionary" : "dictionary/newly_coined_word/newly_coined_word_sungjaefileinc.txt"
  }
}
# tokenizer는 형태소 분석기를 의미하며 korean_nori_toknenizer라는 이름이다.
# nori_tokenizer는 노리 형태소 분석기를 의미한다.
# decompound_level은 형태소 분해 방법이다.
# user_dictionary는 사용자 사전이다. (신조어 사전)

 

 

반응형