Preview
ElasticSearch로 데이터 받아오기
public List<Map<String,Object>> totalSearch(
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();
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
// query에 있는 셋 쿼리 조건으로 걸기
searchSourceBuilder.query(QueryBuilders.matchAllQuery());
// sort 에 있는 셋을 정렬 조건으로 걸기
for(String key : sort.keySet()) {
searchSourceBuilder.sort(new FieldSortBuilder(key).order(sort.get(key)));
}
if(size != null) {
searchSourceBuilder.size(size);
}else {
searchSourceBuilder.size(20);
}
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;
}
- 열심히 검색했지만 전체 index, 전체 field에서 특정 데이터만 들고오는방법을 알수 없음.
ElasticSearch로 특정 데이터 받아오기
elasticSearch에 직접 요청 보내기
- 위의 주소에서 알려준 것처럼 직접 요청을 보냄
String keyword = (String) map.get("keyword");
String url = String.format("http://%s:%d/gaia/_search?q=%s",elUtil.getHostname(),elUtil.getPort(),keyword);
String text = getRequestApiGet(url);
public String getRequestApiGet(String url) throws IOException {
URL obj = new URL(url);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
// optional default is GET
con.setRequestMethod("GET");
// add requesttt header 헤더를 만드는
con.setRequestProperty("Accept-Chatset", "UTF-8");
con.setRequestProperty("Content-Type", "application/json; charset=utf-8");
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
String inputLine;
String resultXmlText = "";
while((inputLine = in.readLine()) != null) {
resultXmlText += inputLine;
}
in.close();
con.disconnect();
return resultXmlText;
}
- utf-8 혹은 euc-kor을 인식하지 못함.
- 간단하게 적었지만 팀장의 도움이 없었다면 상당히 많은 시간을 할애하고 고생했을 듯.
해결
유니코드로 변환 후 전송.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI
- 개발자 툴에 보면 아래 요청이 유니코드로 가는것을 알 수 있음.
- 현재는 한글을 unicode로 변환해서 요청하기 때문에 우측화면처럼 결과값이 잘 받아오지만
- 변환시키기 전에는 요청했던 url이 그대로 출력됨 e.g) &keyword=한글
- 그래서 js에서 $.ajax를 호출하기 전에 변환시켜서 그대로 넘겨줌
keyword = encodeURI(keyword)
- java에서 unicode로 변환시키려다 안되서 js에서 한건 비밀.
ElasticSearch keyup event
- keyUp을 작동시킬 때 setTimeout으로 0.5초마다 값 올리기
$('body').on("keyup", "#dropdownMenuSearchInput",function(e){
let keyword = $(this).val()
console.log($(this).val())
setTimeout("elasticTotalSearch('"+keyword+"')", 2000)
})
- setTimeout이 생각보다 어려웠음.
setTimeout(elasticTotalSearch, 2000) // 파라미터가 존재않으면
setTimeout("elasticTotalSearch('"+keyword+"')", 2000) // 성공
setTimeout("elasticTotalSearch('keyword')", 2000) // 파라미터 keyword를 못찾는다고 뜸
setTimeout(elasticTotalSearch('keyword'), 2000) // setTimeout event가 먹히지 않고 바로 function이 실행.
- 위와 같이 파라미터를 넘기면 작동이 안됨. 삽질을 좀 함.
- 실제 구현 코드
var timer;
$('body').on("keyup", "#dropdownMenuSearchInput",function(e){
console.log($(this).val())
clearTimeout(timer);
let keyword = $(this).val()
timer = setTimeout("elasticTotalSearch('"+keyword+"')", 500)
})
- 타자를 치면 가장 마지막 친 글의 0.5초가 지나야지 요청을 한번 보냄.
elastic에서 받은 데이터 후가공하기
- 검색 결과에 따라 issue, milestone, project, member로 나뉘어서 출력할 예정
- list로 받은 결과를 loop를 돌면서 하나씩 빼주기
e.g 5개의 값을 담고있는 리스트 중 issue에 2개가 포함되어 있으면 해당 리스트에서 2개를 뺀 3개의 값을 담고있는 리스트로 milestone을 검사하게끔.
- code
$.each(res.hits.hits, function(i, hit){
console.log(i)
console.log(hit)
if(key in hit["_source"]){
searchResult = $("#headerTemplate .dropdown-menu.total-search-dropdown").children("a").clone()
if(key == "issue_sid"){
searchResult.html('<i class="icon-fire"></i>'+hit._source.issue_his_cont)
}else if(key == "milest_sid"){
searchResult.html('<i class="icon-fire"></i>'+hit._source.issue_his_cont)
}else if(key == "proj_no"){
searchResult.html('<i class="icon-fire"></i>'+hit._source.proj_title)
}else if(key == "mem_no"){
searchResult.html('<i class="icon-fire"></i>'+hit._source.mem_no)
}
var index = res.hits.hits.indexOf(hit);
if (index !== -1) {
console.log(res.hits.hits.splice(index-cnt, 1));
cnt++;
}
$(".dropdown .dropdown-menu.total-search-dropdown").prepend(searchResult);
}
})
5개의 값 중 이슈에 2개읙 값이 포함되어 있으면 오류가 남. (4째 값이존재하지 않기 때문)
해결 방안
- copyList를 만들고 해당하는 값이 존재하면 이 녀석을 빼준다.(원본말고)
- 해당하는 값이 존재해서 빼 줄때 i를 같이 빼준다.
- 실행해 보니 어림없다. 곰곰히 생각해 보니 말 그대로 어림없는게 맞는듯 하다.
- 우리는 for안에서 i 를 가지고 논다.상단의i에 영향을 주기 위해서는 each문 위에 i를 선언해주거나
- each() 자체를 건들어야할 듯.
- .reverse()를 사용한다. $().reverse().each(function(...){})형태
- 안됨. 문법을 잘 못 썻는지 계속 오류남.
- 이것도 곰곰히 생각해 보고 document를 읽어봤는데 내가 쓸 용도와는 다른 듯 함.
- 나는 0,1,2,3,4,,, 이렇게 읽는게 아니라 4,3,2,1,0 이렇게 읽고 싶은데 reverse는 거꾸로 뒤집어서
- index는 여전히 0,1,2,3,4,,,로 읽는 듯함.
- copyList = res.hits.hits를 하는 순간 서로 주소값이 같아짐.
copyList = new Array[]
copyList = res.hits.hits // 다시 주소값이 같아짐.
- 그러다 ...을 발견.
res.hits.hits = [...copyList]
Summary
- elasticSearch에서 값을 받아오는게 생각보다 힘들었음.
- 값을 받아온 뒤 후처리하는것도 생각보다 힘들었음.
- [...]
Tomorrow
- 통합검색 css를 수정하고
- 좀 더 가다듬고
- 시나리오를 짜면 될 듯 함.
Uploaded by Notion2Tistory v1.1.0