지난 게시글에서는 검색 정렬에 대해서 다뤄봤습니다.
이번에는 검색 조건을 거는 부분. 검색 조건이 중첩되는 부분을 보겠습니다. 소스 먼저 보시죠!
Controller
@RestController
public class TestController {
@Autowired
TestService testService;
@RequestMapping("/test/test.do")
List<Map<String,Object>> test(
@RequestParam(value="sort",defaultValue = "") String sort,
@RequestParam(value="department",defaultValue="") String department,
@RequestParam(value="publisher",defaultValue="") String publisher,
@RequestParam(value="age",defaultValue="") String age
) throws Exception{
return testService.sendHighLevelApi("combook_*", sort, department, publisher, age);
}
}
지난번에 다뤘던 sort 파라미터 뿐만 아니라 department(분야), publisher(출판사), age(적정 연령)에 대한 파라미터를 받았습니다. 각 파라미터들을 메서드에 전달합니다.
ServiceImpl
@Slf4j
@Service
public class TestServiceImpl implements TestService{
@Autowired
RestHighLevelClient client;
@Override
public List<Map<String, Object>> sendHighLevelApi(String indexName, String sort, String department, String publisher,
String age) throws Exception {
ArrayList<Map<String,Object>> list = null;
if("".equals(sort)) sort = "date";
log.debug("sort: "+sort);
log.debug("publisher: " + publisher);
log.debug("department: " + department);
log.debug("age: " + age);
try {
SearchRequest searchRequest = new SearchRequest(indexName);
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.size(10000);
searchSourceBuilder.timeout(new TimeValue(60,TimeUnit.SECONDS));
BoolQueryBuilder query = new BoolQueryBuilder();
if(!"".equals(publisher)) {
query.must(QueryBuilders.matchQuery("publisher.keyword",publisher));
}
if(!"".equals(department)) {
query.must(QueryBuilders.matchQuery("department.keyword", department));
}
if(!"".equals(age)) {
if("초등3학년이상".equals(age) || "초등전학년".equals(age)) {
age = age.concat("-"+age);
}
String minAge = age.split("-")[0];
String maxAge = age.split("-")[1].replaceAll("세", "");
query.must(QueryBuilders.matchQuery("min_age.keyword", minAge));
query.must(QueryBuilders.matchQuery("max_age.keyword", maxAge));
}
if("".equals(publisher) && "".equals(department) && "".equals(age) ) {
searchSourceBuilder.query(QueryBuilders.matchAllQuery());
} else {
searchSourceBuilder.query(query);
}
// sort
if("date".equals(sort)) {
searchSourceBuilder.sort(new FieldSortBuilder("reg_date.keyword").order(SortOrder.ASC)); // 등록일순 정렬
} else if("cheap".equals(sort) ) {
searchSourceBuilder.sort(new FieldSortBuilder("price").order(SortOrder.ASC)); // 등록일순 정렬
} else if("expensive".equals(sort) ) {
searchSourceBuilder.sort(new FieldSortBuilder("price").order(SortOrder.DESC)); // 등록일순 정렬
}
searchSourceBuilder.sort(new ScoreSortBuilder().order(SortOrder.DESC)); // score 높은순 (default)
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
SearchHits hits = searchResponse.getHits();
SearchHit[] searchHits = hits.getHits();
list = new ArrayList<Map<String,Object>>();
for (SearchHit hit : searchHits) {
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
// log.debug("sourceAsMap: " + sourceAsMap);
list.add(sourceAsMap);
}
}catch (Exception e) {
e.printStackTrace();
}
return list;
}
}
여러 조건을 중첩할 때에는 BoolQueryBuilder를 사용합니다.
BoolQueryBuilder에서는 must, should 이 두가지를 제일 많이 사용합니다.
must는 반드시 일치해야 검색 결과가 도출됩니다. (AND 조건)
should는 여러 개 중에 하나만 일치하여도 검색 결과가 도출됩니다. (OR 조건)
저는 must를 사용하여 AND 조건으로 검색 조건을 중첩해보겠습니다!
must의 인자로 QueryBuilder가 들어갑니다. 여러가지 querybuilder 가 있는데, 저는 matchQuery를 사용하였고 matchQuery의 사용 방법은 ("필드명", 쿼리 값)입니다. 이때 필드명. keyword를 하는 이유는 필드명과 정확히 일치할 때 검색 결과가 도출됩니다. keyword가 빠진다면 '도서출판 아람'으로 검색했을 때 '도서출판 무지개', '도서출판 아람' 이렇게 두 결과가 나옵니다.
publisher, department, age의 값이 있을 때 boolquerybuilder에 must메서드로 검색 조건을 추가합니다. 파라미터 3개의 값이 모두 있을 때에는 제 소스의 경우에는 must가 4번 걸리게 되겠네요 !
결과 확인
publisher=교원
출판사가 교원인 문서 4건이 결과로 나왔습니다.
publisher=교원, age=초등전학년
출판사가 교원, 적정 연령이 초등 전 학년인 문서 2건이 검색 결과로 나왔습니다.
publisher=교원, age=초등전학년, department=과학동화
출판사가 교원, 적정 연령이 초등 전 학년, 분야가 과학동화인 문서 1건이 검색 결과로 나왔습니다.