본문 바로가기

스프링

[Spring] elasticsearch NativeQuery (multi_match)

기존의 엘라스틱서치로 multi match를 사용하기 위해서 NativeSearchQuery를 썼었다.

출처 (https://www.baeldung.com/spring-data-elasticsearch-queries)

 

하지만 5.0버전 이상부터는 NativeSearchQuery가 Deprecated되었다,

https://docs.spring.io/spring-data/elasticsearch/docs/current/api/deprecated-list.html

NativeSearchQuery Deprecated

 

NativeQuery

대신 NativeQuery와 Query를 사용하여 multi_match를 구현할 수 있었다.

Query multiMatchQuery = NativeQuery.builder()
        .withQuery(
                q-> q.multiMatch(MultiMatchQuery.of(builder->
                        builder
                                .query(userKeyword)
                                .fields("title^2", "info", "blind_info", "address")
                                .boost(1.5f)
                                .operator(Operator.Or)
                                .type(TextQueryType.MostFields)
                ))
        ).getQuery();

 

 

query 에 사용자의 입력을 넣고 검색할 필드로 "title","info","blind_info","address"를 두었다. 그 중 "title"은 ^2로 표시해 중요도를 높였다. boost로 multiMatch의 결과의 비중을 높일 수 있다. 


multi_match의 type은 크게 best_fileds (기본값), most_fileds가 있는데 자세한건 다음 링크에서 볼 수 있다.

https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-multi-match-query.html

 

Multi-match query | Elasticsearch Guide [8.11] | Elastic

The cross_fields type blends field statistics in a complex way that can be hard to interpret. The score combination can even be incorrect, in particular when some documents contain some of the search fields, but not all of them. You should consider the com

www.elastic.co

 

bool을 사용해서 다른 쿼리들과 함께 should로 묶기 위해 QueryBuilder를 사용했다. 페이징은 NativeQuery를 다시 이용했다.

Query query = QueryBuilders.bool().should(multiMatchQuery).should(keywordMatchQueryList).build()._toQuery();

NativeQuery nativeQuery = NativeQuery.builder()
                .withQuery(query)
                .withPageable(pageable)
        .build();

 

SearchHits<EDestination> response =  elasticsearchOperations.search(nativeQuery, EDestination.class);

 

실제 쿼리는 다음과 같다. 

"Query":{
    "bool":{
        "should":[
        {
            "multi_match":{
                "boost":1.5, 
                "fields":["title^2", "info", "blind_info", "address"],
                "operator":"or",
                "query":"맛집",
                "type":"most_fields"
            }
        }]
    }
}

(keywordMathQueryList는 길어서 생략) 

 

 

더보기

NativeQuery

 

package org.springframework.data.elasticsearch.client.elc;
...

public class NativeQuery extends BaseQuery {
    ...
	public NativeQuery(NativeQueryBuilder builder) {
		super(builder);
		this.query = builder.getQuery();
		this.filter = builder.getFilter();
		this.aggregations.putAll(builder.getAggregations());
		this.suggester = builder.getSuggester();
		this.fieldCollapse = builder.getFieldCollapse();
		this.scriptedFields = builder.getScriptedFields();
		this.sortOptions = builder.getSortOptions();
		this.searchExtensions = builder.getSearchExtensions();
	}
    
    public NativeQuery(@Nullable Query query) {
		this.query = query;
	}


    public static NativeQueryBuilder builder() {
		return new NativeQueryBuilder();
	}
    
    
    ...
}

 

NativeQuery 클래스는 다음과 같다. 기본적으로 Query를 받거나 NativeQueryBuilder를 사용한다. 이외에도 getQuery(), getFilter() 등 기본적인 getter를 지원한다.

 

NativeQueryBuilder

package org.springframework.data.elasticsearch.client.elc;

...
public class NativeQueryBuilder extends BaseQueryBuilder<NativeQuery, NativeQueryBuilder> {
	...
    public NativeQueryBuilder withQuery(Query query) {

		Assert.notNull(query, "query must not be null");

		this.query = query;
		return this;
	}

	public NativeQueryBuilder withQuery(Function<Query.Builder, ObjectBuilder<Query>> fn) {

		Assert.notNull(fn, "fn must not be null");

		return withQuery(fn.apply(new Query.Builder()).build());
	}

    ...
}

 NativeQueryBuilder도 마찬가지로 filter와 query 등에 대해 getter를 지원한다. 핵심적인 쿼리 부분은 Query를 받거나, withQuery로 람다식을 통해 만들 수 있다. 즉 NativeQuery는 Query의 간편한 제작을 제공한다.