Elasticsearch는 관계형 데이터베이스와 다르게 쿼리(Query)와 필터(Filter)를 통해 데이터를 인덱싱 및 서칭 합니다.
쿼리와 필터는 모두 JSON형식으로 구현하며 이 QueryDSL(Domain Specific Language)라고 합니다. 쿼리와 필터는 각각 독립적인 요소로 실행되는데 이들에 대해 상세하게 설명드리도록 하겠습니다.
기본적인 형태소 분석 과정에 대해 설명드리자면, 대문자를 모두 소문자로 변환하고 중복 단어를 제거 후 분석 과정을 거치게 됩니다. 이러한 과정을 거치고 저장된 토큰을 텀(term)이라고 합니다.
이제 쿼리에 대해 하나씩 예시 코드와 함께 설명드리겠습니다.
Indexing
- IndexQuery
- Indexing: 데이터를 검색될 수 있는 토큰으로 변환하기 위해 원본 문서를 검색어 토큰으로 변환하는 과정
- ex) Product Index에 여러 Product를 한꺼번에 추가하는 경우: bulkindex() 적용
@Service
public class ProductSearchService {
private static final String PRODUCT_INDEX = "productindex";
@Autowired private ElasticsearchOperations elasticsearchOperations;
public List<String> createProductIndexBulk(final List<Product> products) {
List<IndexQuery> queryList = products.stream()
.map(product->
new IndexQueryBuilder()
.withId(product.getId().toString())
.withObject(product).build())
.collect(Collectors.toList());
return elasticsearchOperations
.bulkIndex(queryList, IndexCoordinates.of(PRODUCT_INDEX));
}
}
Searching
- Index에서 Document를 검색하기 위한 과정 (RDB 관점: Index=database, document=row)
- Elasticsearch Query Class의 종류
- CriteriaQuery
- StringQuery
- NativeSearchQuery (복잡한 쿼리를 사용하고 Criteria로는 표현이 불가할 때 사용, CriteriaQuery, StringQuery의 단점을 보완한 클래스)
이 세 개의 쿼리 중에서 가장 사용도가 높은 NativeSearchQuery에 대해서 설명드리겠습니다.
NativeSearchQuery의 Query Method 종류
- matchQuery
- multimatchQuery
- termQuery
- termsQuery
- rangeQuery
- boolQuery
이 외에도 QueryBuilders 클래스를 뜯어보면 매우 다양한 쿼리가 있습니다.
저는 자주 쓰는 위의 6개 쿼리에 대해 설명드리겠습니다.
matchQuery
- 특정 필드가 주어진 키워드와 일치하는 문서 검색
- 일반적으로 텍스트 필드에 대한 전문 검색(Full-Text Search)
age가 30인 데이터를 검색하기 위한 matchQuery
PageRequest PageRequest = PageRequest.of(0, 50);
// 요청 결과를 페이지로 가져오기 위한 Pageable 객체, 한 페이지당 50개의 결과를 가져옴
FieldSortBuilder idSortBuilder = SortBuilders.fieldSort("id").order(SortOrder.ASC);
// 검색 결과를 "id" 필드를 기준으로 오름차순 정렬하기 위한 정렬 객체 생성
MatchQueryBuilder matchQueryBuilder = new QueryBuilders.matchQuery("age", 30)
// age 필드가 30인 데이터를 검색하기 위한 매치 쿼리 객체 생성
NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
.withQuery(matchQueryBuilder)
.withPageable(pageRequest)
.withSort(idSortBuilder)
.build();
// ElasticSearch에서 사용할 검색 쿼리를 구성하기 위한 빌더 객체 생성
// 검색 쿼리에 매치 쿼리 설정 (age가 30인 데이터)
// 검색 쿼리에 페이징 요청 설정, 첫번째 데이터를 가져오는데 페이지당 50개의 결과 반환
// 검색 쿼리에 정렬 설정
String query = nativeSearchQuery.getQuery().toString();
// 생성된 검색 쿼리를 문자열로 변환하여 출력
List<Person> content = sampleRepository.search(nativeSearchQuery)
.getContent();
// Elasticsearch에 생성된 검색 쿼리를 실행하고 결과를 가져옴.
multiMatchQuery
- 여러 개의 필드가 특정 키워드와 일치하는 쿼리
id 및 age가 44인 데이터를 검색하기 위한 multiMatchQuery
PageRequest pageRequest = PageRequest.of(0, 50);
FieldSortBuilder idSortBuilder = SortBuilders.fieldSort("id").order(SortOrder.ASC);
MultiQueryBuilder multiQueryBuilder = QueryBuilders.multiMatchQuery("44", "id", "age");
NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
.withQuery(multiQueryBuilder)
.withPageable(pageRequest)
.withSort(idSortBuilder)
.build();
String query = nativeSearchQuery.getQuery().toString();
logger.info(query);
List<Person> content = personRepository.search(nativeSearchQuery).getContent();
termQuery
- term 옵션을 사용하여, 질의문이 저장됨 텀과 정확히 일치하는 내용을 찾는 쿼리
city 필드 값이 변수 "city" 일치하는 데이터를 검색하기 위한 termQuery
TermQueryBuilder query = QueryBuilders.termQuery("city", city);
NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
.withQuery(query)
.build();
termsQuery
- terms 옵션을 사용하여 2개 이상의 텀을 같이 검색할 경우 사용하는 쿼리
- termsQuery의 값은 항상 배열 형식으로 입력
firstname 필드 값이 "vera", "kari", "blake" 중 하나인 데이터를 검색하기 위한 termsQuery
PageRequest pageRequest = PageRequest.of(0, 50);
FieldSortBuilder idSortBuilder = SortBuilders.fieldSort("id").order(SortOrder.ASC);
TermsQueryBuilder termsQueryBuilder = QueryBuilders.termsQuery("firstname", "vera", "kari", "blake");
NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
.withQuery(termsQueryBuilder)
.withPageable(pageRequest)
.withSort(idSortBuilder)
.build();
rangeQuery
- 제공된 범위 내의 데이터를 검색하기 위한 쿼리
- 필드는 숫자 또는 날짜/시간의 경우, JSON의 표준 날짜/시간 입력 형식 이어야 합니다.
- 범위 쿼리에 사용되는 값(gte(>=), gt(>), lte(<=), lt(<))
age 필드 값이 20 ~ 29까지 범위의 데이터를 검색하기 위한 rangeQuery
PageRequest pageRequest = PageRequest.of(0, 50);
FieldSortBuilder idSortBuilder = SortBuilders.fieldSort("id").order(SortOrder.ASC);
RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("age").from(20).to(30)
.includeLower(true).includeUpper(false);
// 20 ~ 30 (age), 하한값 20 포함, 상한값 30 제외
NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
.withQuery(rangeQueryBuilder)
.withPageable(pageRequest)
.withSort(idSortBuilder)
.build();
String query = nativeSearchQuery.getQuery().toString();
List<Person> content = personRepository.search(nativeSearchQuery).getContent();
boolQuery
- 복합 쿼리를 구성하기 위한 쿼리
- 하나의 boolQuery를 생성하고, 해당 Bool 쿼리 메서드 내에서 필터 쿼리와 가장 많은 쿼리를 전달합니다.
- 여러 개의 검색 조건을 조합할 수 있습니다.
- boolQuery의 4개의 인자
- must : Query가 참인 document들을 검색 (AND)
- mustNot : Query가 거짓인 document 검색 (NOT)
- should : 검색 결과 중 이 쿼리에 해당하는 document의 점수를 높임 (OR)
- filter : Query가 참인 document를 검색하지만, 스코어를 계산하지 않고, must보다 검색 속도가 빠르고 캐싱이 가능합니다.
firstname 필드 값이 "Effie", gender 필드 값이 "M", balance 필드 값이 "3607"인 데이터를 검색하기 위한 boolQuery
ageRequest pageRequest = PageRequest.of(0, 50);
FieldSortBuilder idSortBuilder = SortBuilders.fieldSort("id").order(SortOrder.ASC);
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
.must(QueryBuilders.matchQuery("firstname", "Effie"))
.mustNot(QueryBuilders.matchQuery("gender", "M"))
.should(QueryBuilders.matchQuery("balance", "3607"))
// 복합 쿼리를 수행하기 위한 불리언 쿼리 빌더 생성, must, mustNot, should 등의
// 메서드를 사용하여 여러가지 조건 설정 가능
NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder().
.withQuery(boolQueryBuilder)
.withPageable(idSortBuilder)
.with(idSortBuilder)
.build();
// Elasticsearch에서 사용할 검색 쿼리를 구성하기 위한 빌더 객체 생성 및 불리언 쿼리를
// 검색 쿼리에 설정
// 검색 쿼리를 완성하여 NativeSearchQuery 객체 생성
String query = nativeSearchQuery.getQuery().toString();
// 생성된 검색 쿼리를 문자열로 변환하여 출력
List<Person> content = personRepository.search(nativeSearchQuery).getContent();
// Elasticsearch에 생성된 검색 쿼리를 실행하고 결과를 가져옴.
// 이 예시에서는 Person 객체의 리스튿인 content에 검색 결과를 저장 -
이상으로 Elasticsearch에서는 데이터 삽입 및 조회를 어떻게 하는지 쿼리로 알아보았습니다.
'Database > Elasticsearch' 카테고리의 다른 글
[Elasticsearch] Elasticsearch란 무엇이고 왜 사용하는가 (0) | 2023.11.10 |
---|