아빠는 개발자

[Aqqle] API shop service 본문

Aqqle/API

[Aqqle] API shop service

father6019 2025. 1. 4. 21:57
728x90
반응형

 

이것도 정리 한번 해보자 

 

개선 포인트

  1. 가독성 향상:
    • fetchSource 설정을 별도 메서드로 추출하여 주석이나 메서드명을 통해 의도를 명확히 표현할 수 있습니다.
  2. 재사용성 증가:
    • 동일한 SearchSourceBuilder 초기화 로직을 여러 곳에서 사용할 수 있습니다.
  3. 변경 용이성:
    • 나중에 포함하거나 제외할 필드를 수정해야 할 경우, 한 곳에서만 변경하면 됩니다.
  4. 주석 추가:
    • includeFields와 excludeFields의 목적을 설명하면, 다른 개발자가 빠르게 코드를 이해할 수 있습니다.
package com.doo.aqqle.service;


import com.doo.aqqle.HostUrl;
import com.doo.aqqle.component.TextEmbedding;
import com.doo.aqqle.component.query.LocationSearchQuery;
import com.doo.aqqle.component.query.ShopSearchQuery;
import com.doo.aqqle.component.response.DataResponse;
import com.doo.aqqle.dto.TextEmbeddingDTO;
import com.doo.aqqle.model.CommonResult;
import com.doo.aqqle.model.request.LocationRequest;
import com.doo.aqqle.model.request.ShopRequest;
import lombok.RequiredArgsConstructor;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;

@Service
@RequiredArgsConstructor
public class ShopService {

    private final ResponseService responseService;
    private final ShopSearchQuery query;
    private final LocationSearchQuery locaton;
    private final DataResponse response;

    public CommonResult getProducts(ShopRequest request) {

        try {
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            String[] includeFields = new String[]{};
            String[] excludeFields = new String[]{"feature_vector"};
            searchSourceBuilder.fetchSource(includeFields, excludeFields);

            FunctionScoreQueryBuilder.FilterFunctionBuilder[] filterFunctionBuilders = null;

            Script script = new Script(ScriptType.INLINE, Script.DEFAULT_SCRIPT_LANG, "1", new HashMap<>());
            if ("Y".equals(request.getSimilarity())) {
                Vector<Double> vectors = TextEmbedding.getVector(
                        TextEmbeddingDTO.builder()
                                .tensorApiUrl(HostUrl.EMBEDDING.getUrl())
                                .keyword(request.getSearchWord()).build()
                );
                Map<String, Object> map = new HashMap<>();
                map.put("query_vector", vectors);
                script = new Script(ScriptType.INLINE, Script.DEFAULT_SCRIPT_LANG, "cosineSimilarity(params.query_vector, 'feature_vector') + 1.0", map);
            }

            filterFunctionBuilders = query.getShopFunctionScoreQueryBuilder(script);

            FunctionScoreQueryBuilder functionScoreQueryBuilder = new FunctionScoreQueryBuilder(
                    query.getShopQueryBuilder(request.getSearchWord()),
                    filterFunctionBuilders
            );

            LocationRequest locationRequest = new LocationRequest();
            locationRequest.setDistance("5");
            locationRequest.setCountryCode("KR");
            locationRequest.setSize(10);

            Map<String, Object> resultMap = new HashMap<>();
            resultMap.put("LOCATION", response.dataResponse(locaton.getDistanceBuilder(locationRequest), locationRequest));
            resultMap.put("ITEM", response.shopDataResponse(functionScoreQueryBuilder, request));

            return responseService.getSingleResult(resultMap);

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

        return responseService.getFailResult();
    }

}

 

변경된 코드 

 

@Service
@RequiredArgsConstructor
public class ShopService {

    private final ResponseService responseService;
    private final ShopSearchQuery query;
    private final LocationSearchQuery locationQuery;
    private final DataResponse response;

    public CommonResult getProducts(ShopRequest request) {
        try {
            SearchSourceBuilder searchSourceBuilder = initializeSearchSourceBuilder();
            Script script = "Y".equals(request.getSimilarity()) ? createSimilarityScript(request.getSearchWord()) : getDefaultScript();
            FunctionScoreQueryBuilder functionScoreQueryBuilder = buildFunctionScoreQuery(script, request);

            LocationRequest locationRequest = new LocationRequest("5", "KR", 10);
            Map<String, Object> resultMap = new HashMap<>();
            resultMap.put("LOCATION", response.dataResponse(locationQuery.getDistanceBuilder(locationRequest), locationRequest));
            resultMap.put("ITEM", response.shopDataResponse(functionScoreQueryBuilder, request));

            return responseService.getSingleResult(resultMap);

        } catch (IOException e) {
            log.error("Error while fetching products: {}", e.getMessage(), e);
            return responseService.getFailResult();
        }
    }

    private SearchSourceBuilder initializeSearchSourceBuilder() {
        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.fetchSource(new String[]{}, new String[]{"feature_vector"});
        return builder;
    }

    private Script createSimilarityScript(String searchWord) throws IOException {
        Vector<Double> vectors = TextEmbedding.getVector(
                TextEmbeddingDTO.builder()
                        .tensorApiUrl(HostUrl.EMBEDDING.getUrl())
                        .keyword(searchWord).build()
        );
        Map<String, Object> params = new HashMap<>();
        params.put("query_vector", vectors);
        return new Script(ScriptType.INLINE, Script.DEFAULT_SCRIPT_LANG, "cosineSimilarity(params.query_vector, 'feature_vector') + 1.0", params);
    }

    private Script getDefaultScript() {
        return new Script(ScriptType.INLINE, Script.DEFAULT_SCRIPT_LANG, "1", new HashMap<>());
    }

    private FunctionScoreQueryBuilder buildFunctionScoreQuery(Script script, ShopRequest request) {
        FunctionScoreQueryBuilder.FilterFunctionBuilder[] filterFunctionBuilders = query.getShopFunctionScoreQueryBuilder(script);
        return new FunctionScoreQueryBuilder(
                query.getShopQueryBuilder(request.getSearchWord()),
                filterFunctionBuilders
        );
    }
}
728x90
반응형

'Aqqle > API' 카테고리의 다른 글

[Aqqle] API pakage 구성  (0) 2025.01.04
[Aqqle] shop api restcontroller  (0) 2025.01.04
[Aqqle] API architecture  (1) 2024.08.31