스프링 부트 환경에서 솔라 쿼리 사용해서 검색엔진 질의하기
이 글은, 자바(스프링) 클라이언트 환경에서 솔라(Solr) 검색엔진에 데이터를 검색하는 기초적인 방법에 대해서 설명한다. 아주 기초적인 내용이라서, Solr 를 처음 사용하는 개발자에게 추천하는 글이다.
이 글의 주제는 자바 환경에서의 Solr Query 에 대한 글이다. 필자가 운영하는 프로젝트에서는 Elasticsearch와 Solr 를 전부 사용하고 있는데, Solr 는 핵심 검색엔진으로 사용중이다. 물론, 필자의 팀에서 관리하지는 않고, 유관부서에서 색인 및 인덱싱을 맡아서 운영하고, 필자의 애플리케이션에서는 검색쿼리를 통해서 데이터를 조회해서 서비스를 운영하고 있다. 사실, 필자는 전회사에서 검색 도메인에서 업무를 했었지만, 실제로 루씬 기반의 솔라 검색엔진에 대해서 제대로 공부할 기회는 없었다. 이번 기회에 아주 기초적인 쿼리에 대해서 공부할 예정이다. 가능하면 루씬 알고리즘 등 검색 기본 개념에 대해서도 다시 공부를 해보고 싶지만, 시간 관계상 생략하겠다. 아쉽게도, 루씬 알고리즘, 역색인 등 기본적인 검색 알고리즘에 대해서 자세하게 다루지는 않지만, 검색 도메인 업무를 처음 시작하는 개발자는 반드시 루씬 알고리즘에 대해서 공부하고 돌아오길 바란다. 나중에 시간이 되면 각잡고 자세하게 작성을 해보겠다.
이글에서는 루씬, 역색인 등 검색 기초 개념에 대한 자세한 설명을 생략한다. 하지만, 매우 중요한 개념임으로 꼭 숙지하기를 바란다.
참고로, 필자는 Solr(솔라)를 맥북 로컬서버에 설치하였고, 기본 포트인 8983포트를 사용한다. 해당 글에서는 Solr(솔라) 어드민 페이지를 같이 보면서 설명하겠다. (참고로, 개인적으로는 Solr 의 아이콘이 정말 기분 나쁘다...)
필자의 샘플 코드는 스프링부트, 자바 환경에서 작성한다. 아래와 같이 SolrConfig 클래스에 SolrClient 빈을 정의한다.
SolrClient 를 사용하기 위해서, 의존성 주입을 해서 사용하면 된다.
검색엔진에 몇개의 데이터를 색인해서 넣었다.
Solr(솔라) 에 질의하는 검색 쿼리에 대해서 다양하게 살펴보자.
가장 기본적인 쿼리를 사용해보자. 이름에 "라떼"가 포함되어 있는 문서를 찾아보자.
파라미터 q 에 name:라떼 를 입력한 후 조회하면 아래와 같은 결과가 나올 것이다.
참고로, 이름이 "라떼" 인 경우에 score 가 가장 높게 나왔다. 자바 코드로 작성을 해보면 아래와 같다. SolrQuery 를 사용해서 쿼리 파라미터를 만들고, 컨피그에서 설정한 SolrClient 빈을 주입받아서 query 메서드를 실행하면 된다.
SolrDocumentList 는 검색 결과로 부터 리턴받은 결과를 매핑한다.
위와 같이 쿼리를 사용하면, 어렵지 않게 문서를 검색할 수 있다.
검색 요청을 할 때, 몇건의 문서를 검색할지 설정을 할 수 있다. rows 항목에 2를 설정해보자. 아래와 같이 이름에 라떼를 포함한 문서를 딱 2개만 조회한다.
샘플 코드를 보자. 참고로 위에서 작성한 코드에서 살짝 변경이 있다 .
query.set("q","쿼리") --> query.setQuery("쿼리")
SolrDocumentList --> getBeans 구문으로 변경
getBeans(클래스) 메서드를 사용하면 특정 객체에 매핑해서 리턴 받을 수 있다. 필자는, Coffee 라는 이름의 클래스를 정의한 후 Coffee 객체 리스트로 검색 결과를 매핑하였다. 위 코드에서 ROWS 를 설정하는 코드는 query.setRows(int) 구문이다. 해당 구문에 검색 결과로 전달받을 숫자를 작성한다. 필자는 2로 설정했기 때문에 딱 2개의 데이터만 조회할 것이다. 참고로, Score, Sort 에 의해서 검색 결과는 바뀔 수 있는데, 필자가 작성한 코드는 별도로 Sort 를 설정하지 않았는데, 기본 소팅 조건은 score desc 이다.
정렬 조건을 변경해보자. 이름에 "라떼" 라는 문자열이 포함된 문서 중, 가격이 가장 비싼 순으로 조회해보자. 아래와 같이 sort 항목에 price desc 를 추가하고 검색해보자. 아래와 같이 "녹차 라떼"가 조회가 된다.
자바 코드로는 아래와 같다. setSort 메서드를 추가하였다.
Range Queries 는 특정 필드가, 어떤 값의 범위에 속하는 경우를 검색할 때 사용한다. 예를 들어서, 가격이 1400~1500 사이인 상품을 검색한다고 가정해보자. 아래 샘플과 같이 price:[1400 TO 1500] 을 q 항목에 넣고 조회를 해보자.
1500원짜리 "아이스 라떼" 만 검색 결과로 리턴 되었다. 코드로는 아래와 같다.
기본 쿼리에 AND 조건이 가능하다. milk 라는 필드의 값이 true이고, 가격이 800~1300 원인 상품 검색은 어떻게 할까?
스코어에 변화를 주고 싶은 경우에는 어떻게 할 수 있을까? 일반적으로 부스터 라고 표현하는 기능을 사용할 수 있다. 일단, 아래 링크를 참고하자.
http://lucene.apache.org/solr/guide/7_2/the-dismax-query-parser.html#bq-boost-query-parameter
예를 들어서, 문서를 검색 조건에서 특정 카테고리인 경우에 스코어를 더 높게 설정할 수 있을까? 이때 부스터 쿼리를 사용하면 된다. 쿼리에 아래와 같이 category 가 아이스 인 경우에 부스터 효과를 설정했다.
어드민에서 확인해보면 아래와 같다. "아이스 라떼" 의 score 값이 월등히 높게 나온 것을 확인할 수 있다.
부스터 쿼리를 사용하기 전이랑 비교해보자.
사용 전 "아이스 라떼" 의 score : 0.14266998
부스터 쿼리 사용 후 "아이스 라떼"의 score : 0.40419912
Filter Query는 검색 결과에 Score 에 영향을 주지 않으면서, 결과를 필터링 할 수 있는 기능인데, 검색을 효율적으로 하기 위해서 캐싱이 된다. 이름에 "라떼"를 포함하고 있는 검색 결과 중에서, 가격이 1300~1600 사이인 문서를 검색하고자 한다면, 아래 코드와 같이 구현하면 된다.
또는, "라떼" 를 포함하는 검색 결과 중에서, 카테고리가 "아이스"인 결과만 출력하고 싶다면 어떻게 하면 될까?
설명했듯이, Filter Query 는 Score 에 영향을 주지 않는다.
필자는 Solr 검색엔진을 공부한지 하루밖에 안됐다. 그래서 Filter Query 에 대한 개념이 완벽하지 않은 상황이다. 이 글을 읽는 개발자는 해당 글을 100% 믿지 말고, 관련 자료를 찾아서 따로 공부하길 바란다.
생략한다. 나중에 안바쁠 때 각잡고 다시 작성하겠다.
이정도로만 쓰고 글을 마무리하겠다. 별 내용이 없는 글이지만, 아주 기초적인 내용이었고, Solr 를 처음 사용하는 자바&스프링 개발자는 한번 쯤 읽어볼만 한 글이다. 나중에 시간이 되면, 루씬 알고르즘에 대해서 제대로 공부해서 공유를 할 예정이다.