반응형

자소 단위로 한글 검색을 구현하기 위해 아래의 플러그인을 이용하였습니다.

https://github.com/netcrazy/elasticsearch-jaso-analyzer

 

FROM elasticsearch:6.6.0

RUN /usr/share/elasticsearch/bin/elasticsearch-plugin install https://github.com/netcrazy/elasticsearch-jaso-analyzer/releases/download/v6.6.0/jaso-analyzer-plugin-6.6.0.0-plugin.zip

Dockerfile을 작성한 뒤,

$ docker build --tag elasticsearch-custom .

빌드합니다.

$ docker run -p 9200:9200 -p 9300:9300 --name elasticsearch-custom -e "discovery.type=single-node" elasticsearch-custom

컨테이너를 구동합니다.

 

 

elasticsearch 실행 화면

http://<IP주소>:9200/ 접속이 잘 됩니다.

 

 

해당 플러그인 사용법에 따라 설정을 하겠습니다.

$ curl -XPUT -H 'Content-Type: application/json' http://192.168.99.100:9200/search_logs/ -d '{
  "settings": {
    "index": {
      "analysis": {
        "filter": {
          "suggest_filter": {
            "type": "edge_ngram",
            "min_gram": 1,
            "max_gram": 50
          }
        },
        "tokenizer": {
          "jaso_search_tokenizer": {
            "type": "jaso_tokenizer",
            "mistype": true,
            "chosung": false
          },
          "jaso_index_tokenizer": {
            "type": "jaso_tokenizer",
            "mistype": true,
            "chosung": true
          }
        },
        "analyzer": {
          "suggest_search_analyzer": {
            "type": "custom",
            "tokenizer": "jaso_search_tokenizer"
          },
          "suggest_index_analyzer": {
            "type": "custom",
            "tokenizer": "jaso_index_tokenizer",
            "filter": [
              "suggest_filter"
            ]
          }
        }
      }
    }
  }
}'

인덱스를 생성해줍니다.

 

$ curl -XPUT -H 'Content-Type: application/json' http://192.168.99.100:9200/search_logs/_mapping/search_log -d '{
  "properties": {
    "log": {
      "type": "text",
      "store": true,
      "analyzer": "suggest_index_analyzer",
      "search_analyzer": "suggest_search_analyzer",
      "fields" : {
        "raw" : {"type":"keyword"}
      }
    },
    "category": {
      "type": "keyword"
    },
    "timestamp": {
      "type": "date",
      "format": "yyyy-MM-dd HH:mm:ss"
    }
  }
}'

"log" 필드에서 한글 검색을 수행할 것입니다.

기능을 구현하다보니 "text" 타입에는 aggregation을 이용할 수 없었습니다.

그래서 "fields" 속성 하위에 "raw" 속성을 추가하였습니다.

이렇게 하면 "log.raw"를 이용하여 "keyword"타입으로도 aggregation 할 수 있습니다.

이를 이용하여 express로 구현하고 있는 서버에 자동완성기능과 인기검색어를 구현하고자 하였습니다.

var items = [];
var result = await client.search({
  index : 'search_logs',
  type : 'search_log',
  body : {
    "query" : {
        "match" : {"log" : query}
    },
    "aggs" : {
      "byCount" : {
          "terms" : {
              "field" : "log.raw",
              "size" : 15,
              "order" : { "_count" : "desc" }
           }
      }
    },
    "size" : 0
  }
});
items = result.body.aggregations.byCount.buckets.map(x => x.key);
 
 res.json({result:items});

자동완성 기능을 구현하기위한 예시 코드입니다.

쿼리로 받은 스트링을 이용하여 검색을 수행하고, aggregation을 이용하여 "log"의 중복을 제거한 뒤, count순으로 정렬합니다.

 

//"자ㅈ"로 데이터 조회 결과
{
    "result": [
        "자점석",
        "자전거"
    ]
}

수집된 로그를 바탕으로 "자ㅈ"의 검색 결과입니다.

 

var result = await client.search({
    index : 'search_logs',
    type : 'search_log',
    body : {
      "aggs" : {
        "byCount" : {
            "terms" : {
                "field" : "log.raw",
                "order" : {"_count" : "desc"},
                "size":numOfQuery
            }
        }
      },
    "size" : 0
    }
  });
items = result.body.aggregations.byCount.buckets.map(x => x.key);
res.json({result : items});

인기 검색어를 구현하기 위한 예시 코드입니다.

최근 수집된 검색어 데이터에서 중복을 제거하고, count 순으로 조회를 하려고 하였지만, aggregation 파이프라인을 구현하는 중에 자꾸 오류가 났습니다.

그래서 일단 중복을 제거시키고 count 순으로 조회하였습니다.

// 조회 결과
{
    "result": [
        "안녕",
        "자점석",
        "자전거",
        "가",
        "자",
        "하"
    ]
}

수집된 검색어 로그의 count 순으로 정렬되어 결과가 나옵니다.

 

* 플러그인 버전과 맞추기위해 이전 버전의 elasticsearch를 이용하였습니다.

* 예전에 제대로 된 학습이 되지 않은 채로, 단순 기능 구현만을 목적으로 진행하며 작성했던 내용이라 좋은 방법이 아닐 수 있습니다.

반응형

+ Recent posts