본문 바로가기

Elastic Search

[Elastic Search] MBTI 검색 프로젝트 - 2. Emoji 검색 및 Aggregation(3편)

반응형

Re-Index

막상 이모티콘 검색을 해보니 각 원문에서 이모티콘이 얼마나 포함되어 있는지, 어떤 이모티콘이 가장 많이 있는지 검색해보자

그전에 사전 준비 작업으로 text field로 들어간 데이터에서 키워드를 추출(Es 내부에서는 Term)할 수 있도록 인덱스를 구성하고 전체 문서에서 키워드 빈도수를 기준으로 데이터를 추출하는 방법을 찾아봅니다.

인덱스 구성

PUT /mbti_term
{
        "settings": {
            "analysis": {
              "analyzer": {
                "nori_mixed": {
                  "tokenizer": "nori_t_mixed",
                  "filter": "shingle"
                },
                "nori_pos_noun": {
                  "type": "custom",
                  "tokenizer": "nori_t_mixed",
                  "filter": "pos_filter"
                }
              },
              "tokenizer": {
                "nori_t_mixed": {
                  "type": "nori_tokenizer",
                  "decompound_mode": "mixed"
                }
              },
              "filter": {
                "pos_filter": {
                  "type": "nori_part_of_speech",
                  "stoptags": [
                    "VV", "VA", "VX", "VCP", "VCN", "MM", "MAG", "MAJ",
                    "IC", "J", "E",
                    "XPN", "XSA", "XSN", "XSV",
                    "SP", "SSC", "SSO", "SC", "SE",
                    "UNA"
                  ]
                }
              }
            }
          },
        "mappings": {
            "properties": {
                "title": {
                    "type": "text"
                },
                "contents": {
                    "type": "text",
                    "fields": {
                        "full": {
                          "type": "keyword"
                        },
                        "nori_mixed": {
                            "type": "text",
                            "analyzer": "nori_mixed",
                            "search_analyzer": "standard",
                            "fielddata": true,
                            "term_vector": "yes"
                        },
                        "nori_noun": {
                          "type": "text",
                          "analyzer": "nori_pos_noun",
                          "search_analyzer": "standard",
                          "fielddata": true,
                          "term_vector": "yes"
                        }
                    },
                    "fielddata": true,
                    "term_vector": "yes"
                },
                "keyword": {
                    "type": "keyword"
                },
                "platform": {
                    "type": "keyword"
                },
                "published_at": {
                    "type": "date"
                },
                "doc_url": {
                  "type": "text"
                },
                "comment_cnt": {
                    "type": "integer"
                },
                "like_cnt": {
                    "type": "integer"
                }
            }
        }
    }

여기서 핵심은 대상 필드에서 term_vector,fielddata 이다.

"contents": {
      "type": "text",
      "fields": {
          "full": {
            "type": "keyword"
          },
          "nori_mixed": {
              "type": "text",
              "analyzer": "nori_mixed",
              "search_analyzer": "standard",
              "fielddata": true,
              "term_vector": "yes"
          },
          "nori_noun": {
            "type": "text",
            "analyzer": "nori_pos_noun",
            "search_analyzer": "standard",
            "fielddata": true,
            "term_vector": "yes"
          }
      },
      "fielddata": true,
      "term_vector": "yes"
  }

이를 바탕으로 문서에 있는 단어(term)의 수를 계산하는 쿼리를 보면 아래와 같다.

GET mbti_term/_search
{
  "size": 0,
  "aggs": {
    "term_cnt": {
      "terms": {
			  //contents.nori_mixed, contents.nori_noun 등으로도 가능
        "field": "contents",
        "size": 1000
      }
    }
  }
}

여기에 단어의 길이로 정렬하여 목록을 출력하는 방법도 있다. - 링크 (하지만 502 Bad Gateway 에러가 발생한다..)

위의 쿼리에 대한 결과는 아래와 같다.

{
  "took" : 555,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 10000,
      "relation" : "gte"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "term_cnt" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 11058130,
      "buckets" : [
        {
          "key" : "이",
          "doc_count" : 15136
        },
        {
          "key" : "하",
          "doc_count" : 15088
        },
        {
          "key" : "는",
          "doc_count" : 14448
        },
        {
          "key" : "ᆫ",
          "doc_count" : 13909
        },
        {
          "key" : "고",
          "doc_count" : 13348
        },
        {
          "key" : "아",
          "doc_count" : 13032
        },
        {
          "key" : "은",
          "doc_count" : 13015
        },
        {
          "key" : "가",
          "doc_count" : 12940
        },

 

이모티콘 필드 구성

본문에서 어떻게 이모티콘만 추출할 수 있을까?

아래 쿼리를 사용하면 이모티콘이 포함된 본문만 추출할 수 있다.

GET mbti_term/_search
{
  "query": {
    "regexp": {
      "contents": "[\\uD83D\\uDE00-\\uD83D\\uDE4F, \\uD83C\\uDF00-\\uD83D\\uDDFF, \\uD83D\\uDE80-\\uD83D\\uDEFF, \\uD83C\\uDDE0-\\uD83C\\uDDFF]"
    }
  }  
}

콘텐츠에서 이모티콘이 포함된 콘텐츠만 추출하는 것을 완료했습니다. 하지만 이모티콘만 별도의 필드로 저장해서 분석할 수 있도록 분류하는 게 필요할 것 같습니다.

다음에는 실제 인덱스 필드에 이모티콘 값만 저장될 수 있도록 하는 인덱스 구성을 진행해보겠습니다.

반응형