반응형
Recent Posts
Recent Comments
관리 메뉴

개발잡부

[es] 자동완성 3 본문

ElasticStack/Elasticsearch

[es] 자동완성 3

닉의네임 2022. 2. 6. 18:09
반응형

자동완성 API 를 만들어 보자

 

kr-dynalyzer 형태소 분석기를 적용

bool 쿼리 must 에  multi_match 쿼리를 적용하여 만듬

 

auto Index meta 구조

{
   "version":7,
   "mapping_version":1,
   "settings_version":1,
   "aliases_version":2,
   "routing_num_shards":768,
   "state":"open",
   "settings":{
      "index":{
         "routing":{
            "allocation":{
               "include":{
                  "_tier_preference":"data_content"
               }
            }
         },
         "number_of_shards":"3",
         "provided_name":"auto-2022-02-06",
         "creation_date":"1644136846310",
         "analysis":{
            "analyzer":{
               "chosung-analyzer":{
                  "filter":[
                     "doo-chosung"
                  ],
                  "type":"custom",
                  "tokenizer":"standard"
               },
               "jamo-analyzer":{
                  "filter":[
                     "doo-jamo"
                  ],
                  "type":"custom",
                  "tokenizer":"standard"
               },
               "spell-analyzer":{
                  "filter":[
                     "doo-spell"
                  ],
                  "type":"custom",
                  "tokenizer":"standard"
               },
               "eng2kor-analyzer":{
                  "filter":[
                     "doo-eng2kor"
                  ],
                  "type":"custom",
                  "tokenizer":"standard"
               },
               "kor2eng-analyzer":{
                  "filter":[
                     "doo-kor2eng"
                  ],
                  "type":"custom",
                  "tokenizer":"standard"
               }
            }
         },
         "number_of_replicas":"0",
         "uuid":"DWu2inwrT9uLCDcjZgotkQ",
         "version":{
            "created":"7150199"
         }
      }
   },
   "mappings":{
      "_doc":{
         "properties":{
            "name":{
               "type":"text",
               "fields":{
                  "spell":{
                     "analyzer":"spell-analyzer",
                     "type":"text"
                  },
                  "eng2kor":{
                     "analyzer":"eng2kor-analyzer",
                     "type":"text"
                  },
                  "chosung":{
                     "analyzer":"chosung-analyzer",
                     "type":"text"
                  },
                  "jamo":{
                     "analyzer":"jamo-analyzer",
                     "type":"text"
                  },
                  "kor2eng":{
                     "analyzer":"kor2eng-analyzer",
                     "type":"text"
                  },
                  "keyword":{
                     "type":"keyword"
                  }
               }
            }
         }
      }
   },
   "aliases":[
      "auto"
   ],
   "primary_terms":{
      "0":1,
      "1":1,
      "2":1
   },
   "in_sync_allocations":{
      "0":[
         "34nJn22SQoSszYj96keaeQ"
      ],
      "1":[
         "bHL4bq_bRJeZaq6AF03x5A"
      ],
      "2":[
         "j---jqxARn6-XJWoVE-3mA"
      ]
   },
   "rollover_info":{
      
   },
   "system":false,
   "timestamp_range":{
      "unknown":true
   }
}

 

이걸 java high level client 로 만들면

 

package com.bbongdoo.doo.apis;

import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;

import java.io.IOException;

public class IndexAutoApi {

    public static CreateIndexRequest createIndex(String indexName) throws IOException {
        CreateIndexRequest request = new CreateIndexRequest(indexName);
        request.settings(Settings.builder()
                .put("index.number_of_shards", 3)
                .put("index.number_of_replicas", 0)
        );

        XContentBuilder settingBuilder = XContentFactory.jsonBuilder()
                .startObject()
                    .field("number_of_shards", 3)
                    .field("number_of_replicas", 0)
                    .startObject("analysis")
                        .startObject("analyzer")
                            .startObject("jamo-analyzer")
                                .field("type", "custom")
                                .field("tokenizer", "standard")
                                .array("filter", new String[]{
                                                "doo-jamo"
                                        }
                                )
                            .endObject()

                            .startObject("chosung-analyzer")
                                .field("type", "custom")
                                .field("tokenizer", "standard")
                                .array("filter", new String[]{
                                                "doo-chosung"
                                        }
                                )
                            .endObject()

                            .startObject("eng2kor-analyzer")
                                .field("type", "custom")
                                .field("tokenizer", "standard")
                                .array("filter", new String[]{
                                                "doo-eng2kor"
                                        }
                                )
                            .endObject()

                            .startObject("kor2eng-analyzer")
                                .field("type", "custom")
                                .field("tokenizer", "standard")
                                .array("filter", new String[]{
                                                "doo-kor2eng"
                                        }
                                )
                            .endObject()

                            .startObject("spell-analyzer")
                                .field("type", "custom")
                                .field("tokenizer", "standard")
                                .array("filter", new String[]{
                                                "doo-spell"
                                        }
                                )
                            .endObject()
                        .endObject()
                    .endObject()
                .endObject();
        request.settings(settingBuilder);

        XContentBuilder builder = XContentFactory.jsonBuilder();
        builder.startObject();
        {
            builder.startObject("properties");
            {
                builder.startObject("name");
                {
                    builder.field("type", "text");
                    builder.startObject("fields");
                        builder.startObject("jamo");
                            builder.field("type", "text");
                            builder.field("analyzer", "jamo-analyzer");
                        builder.endObject();
                        builder.startObject("chosung");
                            builder.field("type", "text");
                            builder.field("analyzer", "chosung-analyzer");
                        builder.endObject();
                        builder.startObject("eng2kor");
                            builder.field("type", "text");
                            builder.field("analyzer", "eng2kor-analyzer");
                        builder.endObject();
                        builder.startObject("kor2eng");
                            builder.field("type", "text");
                            builder.field("analyzer", "kor2eng-analyzer");
                        builder.endObject();
                        builder.startObject("spell");
                            builder.field("type", "text");
                            builder.field("analyzer", "spell-analyzer");
                        builder.endObject();
                        builder.startObject("keyword");
                            builder.field("type", "keyword");
                        builder.endObject();
                    builder.endObject();
                }
                builder.endObject();
            }
            builder.endObject();
        }
        builder.endObject();

        request.mapping(builder);
        return request;

    }
}

이렇게 

 

여기에 상품 데이터 name (상품명을 색인 해버림)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

이걸 API 에서 조회 하면

package com.bbongdoo.doo.service;

import com.bbongdoo.doo.component.TextEmbedding;
import com.bbongdoo.doo.dto.TextEmbeddingDTO;
import com.bbongdoo.doo.model.response.CommonResult;
import lombok.RequiredArgsConstructor;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScriptScoreFunctionBuilder;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.*;

@Service
@RequiredArgsConstructor
public class AutoService {

    private final ResponseService responseService;
    private final RestHighLevelClient client;
    private final String ALIAS = "auto";

    public CommonResult getProducts(String searchWord) {

        SearchRequest searchRequest = new SearchRequest();
        searchRequest.indices(ALIAS);
        try {
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

            QueryBuilder queryBuilder =
                    QueryBuilders.boolQuery().must(
                            QueryBuilders.multiMatchQuery(searchWord, "name.jamo", "name.chosung","name.eng2kor", "name.kor2eng","name.spell", "name.keyword")
                    );

            searchSourceBuilder.query(queryBuilder);
            searchSourceBuilder.size(10);
            searchRequest.source(searchSourceBuilder);

            System.out.println(searchRequest.source());
            SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);

            List<Map<String, Object>> returnValue = new ArrayList<>();
            SearchHit[] results = searchResponse.getHits().getHits();

            Arrays.stream(results).forEach(hit -> {
                Map<String, Object> result = hit.getSourceAsMap();
                returnValue.add(result);
            });

            return responseService.getListResult(returnValue);

        } catch (IOException e) {
            e.printStackTrace();
        }


        return new CommonResult();
    }

}

 

검색어 : ㄹㅇ

하면 아래와 같이 나온다

 

역시나 너무 대충 만들었네 

검색어 : skdlzl  <--- 나이키 

 

이기 뭐꼬

반응형

'ElasticStack > Elasticsearch' 카테고리의 다른 글

[es] script_fields  (0) 2022.04.08
[es] payload score  (0) 2022.02.20
[es] 쿼리를 확인해보자  (0) 2022.01.30
[es] 검색쿼리를 만들어 보자 3  (0) 2022.01.30
[es] 검색쿼리를 만들어 보자 2  (0) 2022.01.29
Comments