Java 에서 Elastic Search 사용하기3. - 간단 검색하기

작성: 2021.06.08

수정: 2021.06.08

읽는시간: 00 분

Data/Search Engine

반응형

https://www.elastic.co/guide/en/elasticsearch/client/java-rest/master/_search_apis.html

 

Search APIs | Java REST Client [master] | Elastic

 

www.elastic.co

 

이번에는 엘라스틱 서치를 사용하는 이유인 검색을 해 보도록 하겠습니다. 일단 작성한 코드 먼저 보여드리겠습니다.

 

client로 search 명령을 주면 , response를 return 합니다.

해당 response는 SearchHits 라는 Iterable 구현체를 가지고 있습니다.

지네릭 타입은 SearchHit 입니다.

 

 해당 SerarchHit에서 각각 source를 getSourceAsMap() 메서드를 통해 받고, 모두 list에 추가 해 줍니다.

그러면 검색 결과를 간단하게 Map에 담아 반환 받을 수 있습니다.

RestHighLevelClient의 search 메서드는 parameter로 SearchRequest와 RequestOption을 받습니다.

searchRequest는 다음과 같이 만들었습니다.

 

이렇게 해서 index와 query, sort 를 파라미터로 받아 간단한 검색을 한 뒤 List<Map<String,Object>> 형태로 반환하는 메서드를 만들었습니다.

 

코드를 한번 실행 해 보겠습니다.

package shane;

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

import org.elasticsearch.search.sort.SortOrder;

import best.gaia.utils.ElasticUtil;

public class ElasticSearchTest {
	
	public static void main(String[] args) throws IOException {
		
		ElasticUtil elastic = ElasticUtil.getInstance();
		
		String index = "alarm";
		
		Map<String,Object> query = new HashMap<>();
		query.put("mem_no",4);
		
		Map<String,SortOrder> sort = new HashMap<>();
		sort.put("date",SortOrder.DESC);
		
		List<Map<String, Object>> list = elastic.simpleSearch(index, query, sort);
		for(Map<String, Object> map : list) {
			System.out.println(map);
		}
	}
}

alarm 이라는 index 에서 mem_no 는 4 에 해당하는 document 들을 불러와 date 의 내림차순대로 정렬하라는 명령을 내려 보겠습니다.

나름 생각보다 어렵지 않게 원하는 결과를 조회 받을 수 있었습니다. 

오늘 짜둔 간단한 코드 아래 올려드릴 테니 참고해서 사용해주세요

package best.gaia.utils;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.http.HttpHost;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;

import com.ibatis.common.resources.Resources;


public class ElasticUtil {
	private static ElasticUtil self;
	private RestClientBuilder restClientBuilder;
	
	private ElasticUtil() {
        Properties properties = new Properties();
		try {	// dbinfo.properties에서 접속 정보 받아옵니다.
			properties.load(Resources.getResourceAsReader("best/gaia/db/dbinfo.properties"));
		} catch (IOException e) {}
        String hostname = properties.getProperty("el.url");
        int port = Integer.parseInt(properties.getProperty("el.port"));
        HttpHost host = new HttpHost(hostname, port);
        restClientBuilder = RestClient.builder(host);
	};
	
	public static ElasticUtil getInstance() {
		if(self == null)
			self = new ElasticUtil();
		return self;
	}
	
	public List<Map<String,Object>> simpleSearch(
			String index
			, Map<String,Object> query
			, Map<String,SortOrder> sort
			){
		
		// search에 index 조건 걸기
		SearchRequest searchRequest = new SearchRequest(index);
		SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
		
		// query에 있는 셋 쿼리 조건으로 걸기
		for(String key : query.keySet()) {
			searchSourceBuilder.query(QueryBuilders.matchQuery(key, query.get(key)));
		}
		
		// sort 에 있는 셋을 정렬 조건으로 걸기
		for(String key : sort.keySet()) {
			searchSourceBuilder.sort(new FieldSortBuilder(key).order(sort.get(key)));
		}
		
		searchRequest.source(searchSourceBuilder);
		
		List<Map<String,Object>> list = new ArrayList<>();
		try(RestHighLevelClient client = new RestHighLevelClient(restClientBuilder)) {
			SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
			SearchHits searchHits = response.getHits();
			for(SearchHit hit : searchHits) {
				Map<String, Object> sourceMap = hit.getSourceAsMap();
				list.add(sourceMap);
			}
		} catch (IOException e) {}
		
		return list;
		
	}
	
	public Map<String,Object> getReponse(String index, String id){
		
		GetResponse response = null; 
		
		GetRequest getRequest = new GetRequest(index, id);
		RequestOptions options = RequestOptions.DEFAULT;
		try (RestHighLevelClient client = new RestHighLevelClient(restClientBuilder)) {
			response = client.get(getRequest, options);
		} catch (IOException e) {}
		
		return response.getSourceAsMap();
	}
	
	public int insert(String index, String id, Map<String, Object> data ){
		IndexResponse response = null;
		try(RestHighLevelClient client = new RestHighLevelClient(restClientBuilder)) {
			data.put("date", LocalDateTime.now());
			XContentBuilder xContent = XContentFactory.jsonBuilder().map(data);
			String jsonBody = Strings.toString(xContent);
			
			IndexRequest indexRequest = new IndexRequest(index).id(id).source(jsonBody, XContentType.JSON);
			response = client.index(indexRequest, RequestOptions.DEFAULT);
		} catch (IOException e) {}
		
		return response.getShardInfo().getSuccessful();
	}

}

나름 위에서 작성한 유틸을 바탕으로 service 와 dao를 만들어서 잘 활용 해 보고 있습니다.

 

잘 이해가 되지 않는 다면 가장 쉬운 1번글 부터 차근차근 보면 어렵지 않게 이해하실 수 있을 겁니다.

https://shanepark.tistory.com/139

 

Java 에서 Elastic Search 사용하기 - Get Request

org.elasticsearch elasticsearch 7.12.1 org.elasticsearch.client elasticsearch-rest-high-level-client 7.12.1 Elastic Search client로는 High level client 와 Low level client가 있습니다. low level clie..

shanepark.tistory.com

 

 

 

 

 

+ 추가로 모듈화 후 현재 Spring bean에 등록해서 사용 중인 Component 입니다.

package best.gaia.utils;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.http.HttpHost;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.stereotype.Component;

import com.ibatis.common.resources.Resources;

@Component
public class ElasticUtil {
	private RestClientBuilder restClientBuilder;
	
	private ElasticUtil() {
        Properties properties = new Properties();
		try {	// dbinfo.properties에서 접속 정보 받아옵니다.
			properties.load(Resources.getResourceAsReader("best/gaia/db/dbinfo.properties"));
		} catch (IOException e) {}
        String hostname = properties.getProperty("el.url");
        int port = Integer.parseInt(properties.getProperty("el.port"));
        HttpHost host = new HttpHost(hostname, port);
        restClientBuilder = RestClient.builder(host);
	};
	
	/**
	 * @param index
	 * @param query Map<String, Object> key는 프로퍼티명, object는 value 조건
	 * @param sort Map<String, SortOrder>
	 * @param size (null 넣을 수 있습니다. size null일 경우 모두 받아옴)
	 * @return 
	 */
	public List<Map<String,Object>> simpleSearch(
			String index
			, Map<String,Object> query
			, Map<String,SortOrder> sort
			, Integer size
			){
		/*
		 * search API 참고 주소
		 * https://www.elastic.co/guide/en/elasticsearch/client/java-rest/master/java-rest-high-search.html
		 */
		
		// search에 index 조건 걸기
		SearchRequest searchRequest = new SearchRequest(index);
		SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
		
		// query에 있는 셋 쿼리 조건으로 걸기
		for(String key : query.keySet()) {
			searchSourceBuilder.query(QueryBuilders.matchQuery(key, query.get(key)));
		}
		
		// sort 에 있는 셋을 정렬 조건으로 걸기
		for(String key : sort.keySet()) {
			searchSourceBuilder.sort(new FieldSortBuilder(key).order(sort.get(key)));
		}
		
		if(size != null) {
			searchSourceBuilder.size(size);
		}
		
		searchRequest.source(searchSourceBuilder);
		
		List<Map<String,Object>> list = new ArrayList<>();
		try(RestHighLevelClient client = new RestHighLevelClient(restClientBuilder)) {
			SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
			SearchHits searchHits = response.getHits();
			for(SearchHit hit : searchHits) {
				Map<String, Object> sourceMap = hit.getSourceAsMap();
				list.add(sourceMap);
			}
		} catch (IOException e) {}
		
		return list;
		
	}
	
	public Map<String,Object> getReponse(String index, String id){
		
		GetResponse response = null; 
		
		GetRequest getRequest = new GetRequest(index, id);
		RequestOptions options = RequestOptions.DEFAULT;
		try (RestHighLevelClient client = new RestHighLevelClient(restClientBuilder)) {
			response = client.get(getRequest, options);
		} catch (IOException e) {}
		
		return response.getSourceAsMap();
	}
	
	public int insert(String index, Map<String, Object> data ){
		IndexResponse response = null;
		try(RestHighLevelClient client = new RestHighLevelClient(restClientBuilder)) {
			data.put("date", LocalDateTime.now());
			XContentBuilder xContent = XContentFactory.jsonBuilder().map(data);
			String jsonBody = Strings.toString(xContent);
			
			// id 없이 삽입시 자동 UID가 생성됩니다.
			String id = null;
			IndexRequest indexRequest = new IndexRequest(index).id(id).source(jsonBody, XContentType.JSON);
			response = client.index(indexRequest, RequestOptions.DEFAULT);
		} catch (IOException e) {}
		
		return response.getShardInfo().getSuccessful();
	}

}
반응형