*Elastic Search 공식문서 참조 (https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/java-rest-high.html)
* 현재 구동중인 Elastic Search에는 KOSPI 관련 인덱스(주가, 종목명 , 코드) "Stockinfo2"가 저장되어 있는 상태
1. Client initializing
Maven 의존성 추가
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.6.2</version>
</dependency>
접속하려는 Elastic search API와 동일한 버젼의 클라이언트를 추가하여야 한다
RestHighLevelClient client;
public void init()
{
client = new RestHighLevelClient(
RestClient.builder(
new HttpHost("localhost", 9200, "http"),
new HttpHost("localhost", 9201, "http")));
}
High Level 클라이언트를 초기화 한다. 엘라스틱 서치가 동작하고 있는 Host,Port,프로토콜을 추가하고 클라이언트를 초기화 한다.
*DSL 문법을 모를시
GET /_sql/translate
{
"query": "select * from stockinfo2 where Price='236000'"
}
Kibana에서 위와 같이 SQL문을 번역 할 수 있음
2. 기본 Search
검색하려는 DSL쿼리(Stockinfo2 에서 Price가 236000인 종목 검색)
POST stockinfo2/_search
{
"query" : {
"term" : {
"Price" : {
"value" : "236000",
"boost" : 1.0
}
}
},
"_source" : {
"includes" : [
"@version",
"Code",
"Price"
],
"excludes" : [ ]
},
"docvalue_fields" : [
{
"field" : "@timestamp",
"format" : "epoch_millis"
},
{
"field" : "Name"
},
{
"field" : "Time",
"format" : "epoch_millis"
}
],
"sort" : [
{
"_doc" : {
"order" : "asc"
}
}
]
}
public List<Map<String, Object>> search_basic()
{
//make Result Set
List <Map<String, Object>> arrList = new ArrayList<>();
//Create Search Request
SearchRequest searchRequest = new SearchRequest("stockinfo2");
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(QueryBuilders.termQuery("Price", 236000));
sourceBuilder.from(0);
sourceBuilder.size(10);
//Add Builder to Search Request
searchRequest.source(sourceBuilder);
//Execution(Sync)
try {
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
for(SearchHit s:searchResponse.getHits().getHits())
{
Map<String, Object>
sourceMap = s.getSourceAsMap();
arrList.add(sourceMap);
}
return arrList;
} catch (IOException e) {
System.err.println("Elastic search fail");
}
return null;
}
1. 검색 결과는 Hashmap을 가지고 있는 List로 return
2. terms, match등 하나의 조건만 추가 가능
3. SearchRequest 객체를 생성하면서 조회할 인덱스 지정
4. QueryBuilder를 생성하고 이를 활용해서 termQuery,matchQuery등 메서드를 동작하면 QueryBuilder에 Post 요청가능한 JSON 형태로 Query가 등록됨
5. size,from 등 Option을 설정하고 SearchRequest에 QueryBuilder를 등록
6. SearchRequest를 통해 검색을 수행하고 SearchResponse에 저장
7. SearchResponse는 다음과 같은 형태로 저장
{
"took" : 4,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 2,
"relation" : "eq"
},
"max_score" : null,
"hits" : [
{
"_index" : "stockinfo2",
"_type" : "_doc",
"_id" : "f1YQWHMBd7oqU9TiDouz",
"_score" : null,
"_source" : {
"Price" : "236000",
"@version" : "1",
"Code" : "034730"
},
"fields" : {
"@timestamp" : [
"1594910314055"
],
"Time" : [
"1594942680000"
],
"Name" : [
"SK"
]
},
"sort" : [
525
]
},
{
"_index" : "stockinfo2",
"_type" : "_doc",
"_id" : "dDqydnMB4TK-vb17NjFf",
"_score" : null,
"_source" : {
"Price" : "236000",
"@version" : "1",
"Code" : "002960"
},
"fields" : {
"@timestamp" : [
"1595424257520"
],
"Time" : [
"1595456640000"
],
"Name" : [
"한국쉘석유"
]
},
"sort" : [
2928
]
}
]
}
}
원하는 결과는 Hits -> Hits -> _Source 속의 본문 데이터 이므로 gethits 메서드를 수행하여 해당 데이터를 가져옴
- gethits 말고도 원하는 값을 다른 메서드로 가져 올 수 있음
- Source와 같은 여러개의 데이터가 저장될 수 있는 부분은 List형태로 저장되며 여러개의 내부 필드가 존재하는 부분은 Hashmap으로 저장됨
3. 여러 개 의 SearchResult 검색
public List<Map<String, Object>> search_multi()
{
//Create Search Request
MultiSearchRequest requests = new MultiSearchRequest();
SearchRequest searchRequest = new SearchRequest("stockinfo2");
SearchRequest searchRequest2 = new SearchRequest("stockinfo2");
//Using Search Source Builder
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(QueryBuilders.termQuery("Price", "236000"));
sourceBuilder.from(0);
sourceBuilder.size(5);
SearchSourceBuilder sourceBuilder2 = new SearchSourceBuilder();
sourceBuilder2.query(QueryBuilders.termQuery("Price", "54400"));
sourceBuilder2.from(0);
sourceBuilder2.size(5);
//Add Builder to Search Request
searchRequest.source(sourceBuilder);
searchRequest2.source(sourceBuilder2);
requests.add(searchRequest);
requests.add(searchRequest2);
//Execution(Sync)
try {
MultiSearchResponse searchResponse = client.msearch(requests, RequestOptions.DEFAULT);
List <Map<String, Object>> arrList = new ArrayList<>();
for(Item i:searchResponse.getResponses())
{
for(SearchHit s:i.getResponse().getHits().getHits())
{
Map<String, Object>
sourceMap = s.getSourceAsMap();
arrList.add(sourceMap);
}
}
return arrList;
} catch (IOException e) {
System.err.println("Elastic search fail");
}
return null;
}
1. 기본 Search API에서 Request와 Response가 MultSearch 객체로 변환
2. MultiSearchRequest에 여러개의 searchQueryBuilder를 추가하여 저장
3. MultiSearchResponse에는 Item 객체 배열 형태로 각 저장값이 저장되며 저장된 Item은 각 쿼리들의 Basic Search의 결과값이 저장됨 (List<Hashmap<String,Object>>)
4. 여러개의 검색을 동시에 수행하여 결과물을 하나의 객체로 받아올 수 있음
5. SQL에서 Where절의 OR을 추가하는 효과
4. 여러개의 조건을 가진 쿼리 검색
*검색하려는 DSL쿼리 ( Name이 SK이면서 Price가 236000)
POST stockinfo2/_search
{
"query" : {
"bool" : {
"must" : [
{
"term" : {
"Name" : {
"value" : "SK",
"boost" : 1.0
}
}
},
{
"term" : {
"Price" : {
"value" : 236000,
"boost" : 1.0
}
}
}
],
"adjust_pure_negative" : true,
"boost" : 1.0
}
},
"_source" : {
"includes" : [
"@version",
"Code",
"Price"
],
"excludes" : [ ]
},
"docvalue_fields" : [
{
"field" : "@timestamp",
"format" : "epoch_millis"
},
{
"field" : "Name"
},
{
"field" : "Time",
"format" : "epoch_millis"
}
],
"sort" : [
{
"_doc" : {
"order" : "asc"
}
}
]
}
* 위와 같이 조건이 여러개 붙은 쿼리는 단순하게 term와 같은 형태로 검색할 수 없고 bool값을 응용하여 검색하여야 한다. 이때 사용하는 API 메서드가 아래와 같이 달라진다.
public List<Map<String, Object>> search_bool()
{
//Create Search Request
SearchRequest searchRequest = new SearchRequest("stockinfo2");
//Using Search Source Builder
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
BoolQueryBuilder query = new BoolQueryBuilder();
query.must(QueryBuilders.termQuery("Price", "236000"));
query.must(QueryBuilders.termQuery("Name", "SK"));
sourceBuilder.query(query);
sourceBuilder.from(0);
sourceBuilder.size(10);
//Add Builder to Search Request
searchRequest.source(sourceBuilder);
//Execution(Sync)
try {
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
List <Map<String, Object>> arrList = new ArrayList<>();
for(SearchHit s:searchResponse.getHits().getHits())
{
Map<String, Object>
sourceMap = s.getSourceAsMap();
arrList.add(sourceMap);
}
return arrList;
} catch (IOException e) {
System.err.println("Elastic search fail");
}
return null;
}
1. 기본 검색 방식은 Static메서드들을 활용하여 SearchRequest에 추가하였지만 조건이 여러개 붙는다면 BoolQueryBuilder객체를 생성하고 이에 쿼리를 추가하는 식으로 동작
2.DSL에서와 같이 Bool->Must->Terms 순서로 메서드들 호출하여 쿼리를 저장
3. BoolQuery를 searchRequest에 추가하고 SearchResponse는 기존과 같은 방식으로 동작
4. Muti-Search와 혼합하여 동작 가능
5. SQL구문에서 Where절에 AND를 추가한 효과