반응형

query_string 쿼리는 여러 조건을 조합하기에는 용이한 문법이지만 옵션이 한정되어 있다.

여러 쿼리를 조합하기 위해서는 상위에 bool 쿼리를 사용하고 그 안에 다른 쿼리들을 넣는 식으로 사용 가능하다.

 

bool 쿼리는 4개의 인자를 가지고 있고, 그 인자 안에 다른 쿼리들을 배열로 넣는 방식으로 동작한다.

 

 

  • must : 쿼리가 참인 도큐먼트들을 검색
  • must_not : 쿼리가 거짓인 도큐먼트들을 검색
  • should : 검색 결과 중 이 쿼리에 해당하는 도큐먼트의 점수를 높인다
  • filter : 쿼리가 참인 도큐먼트를 검색하지만 스코어를 계산하지 않는다. must 보다 검색 속도가 빠르고 캐싱이 가능.

 

GET <인덱스명>/_search
{
  "query": {
    "bool": {
      "must": [
        { <쿼리> }, …
      ],
      "must_not": [
        { <쿼리> }, …
      ],
      "should": [
        { <쿼리> }, …
      ],
      "filter": [
        { <쿼리> }, …
      ]
    }
  }
}

 

and 조건으로 검색하려면

must 배열안에 여러개의 조건을 추가해야 한다.

 

예를 들어 match 해당 기간동안 logDate의 로그에 어떤 text 를 가진 데이터 조회를 할 경우

GET 인덱스/_search
{
  "query": { 
    "bool": { 
      "must": [
        {
          "match": {
              "text": "텍스트"
          }
        },
        { 
          "range": { 
             "logDate": {
                  "gte": "2021-06-29 11:00:00.000",
                  "lte": "2021-06-29 12:00:00.000",
                  "format": "yyyy-MM-dd HH:mm:ss.SSS",
                  "time_zone": "+09:00"
             }
          }
        }
      ]
    }
  }
}

 

 

or 조건으로 검색하려면 must : [{match :"A B"}] 와 같이 검색하자.

 

 

 

참고문헌

> https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-query.html [bool 쿼리 공식문서]

> https://esbook.kimjmin.net/05-search/5.2-bool [블로그 Elastic 가이드북]

반응형

'DB > Elasticsearch' 카테고리의 다른 글

[ELK] logstash filter grok 사용  (0) 2022.12.18
반응형

ElasticsearchRepository search 메소드 내부에 NativeSearchQuery 를 넘겨 사용 가능하다.

또는 ElasticsearchTemplate 및 elasticsearchOperations 을 사용할떄도 NativeSearchQuery 를 사용할 수 있다.

 

쿼리 클래스의 종류로는 

CriteriaQuery, StringQuery, NativeSearchQuery

 

NativeSearchQuery 란 

복잡한 쿼리를 사용하려 할때 Criteria 로는 표현이 불가할때 사용한다.

CriteriaQuery 와 StringQuery 의 단점을 보완한 클래스이다.

 

ElasticsearchRepository 를 상속받아 사용하는 방식

@Repository
public interface PersonRepository extends ElasticsearchRepository<Person, String> {

}

또는 

ElasticsearchOperations elasticsearchOperations 을 사용하여 사용가능하다.

@Resource
ElasticsearchOperations elasticsearchOperations;

@Resource
PersonRepository personRepository;

 

두 클래스 중 하나를 사용하면 된다. elasticsearchOperations 은 elasticsearchTemplate 을 구현한 것이라 같게 봤다.

쿼리메소드 종류

matchQuery

//    GET /person/_search
//    {
//        "query": {
//        	"age": 30
//    	   }
//    }
// age 가 30 인 데이터
PageRequest pageRequest = PageRequest.of(0, 50);
FieldSortBuilder idSortBuilder = SortBuilders.fieldSort("id").order(SortOrder.ASC);
MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("age", 30);

NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
.withQuery(matchQueryBuilder)
.withPageable(pageRequest)
.withSort(idSortBuilder)
.build();

String query = nativeSearchQuery.getQuery().toString();
logger.info(query);
List<Person> content = sampleRepository.search(nativeSearchQuery).getContent();
// 쿼리스트링으로도 가능

termsQuery

//{
//  "query": {
//    "terms": {
//      "firstname": ["vera", "kari"]
//    }
//  }
//}

PageRequest pageRequest = PageRequest.of(0, 50);
FieldSortBuilder idSortBuilder = SortBuilders.fieldSort("id").order(SortOrder.ASC);
TermsQueryBuilder termsQueryBuilder = QueryBuilders.termsQuery("firstname", "vera", "kari", "blake");
//term 
//TermsQueryBuilder termsQueryBuilder = QueryBuilders.termsQuery("firstname", "Vera", "Kari", "Blake");
NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
.withQuery(termsQueryBuilder)
.withPageable(pageRequest)
.withSort(idSortBuilder)
.build();
String query = nativeSearchQuery.getQuery().toString();
logger.info(query);
List<Person> content = personRepository.search(nativeSearchQuery).getContent();

multiMatchQuery

// id 와 age 가 44 인 것 찾기

PageRequest pageRequest = PageRequest.of(0, 50);
FieldSortBuilder idSortBuilder = SortBuilders.fieldSort("id").order(SortOrder.ASC);
MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("44", "id", "age");
NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
.withQuery(multiMatchQueryBuilder)
.withPageable(pageRequest)
.withSort(idSortBuilder)
.build();
String query = nativeSearchQuery.getQuery().toString();
logger.info(query);
List<Person> content = personRepository.search(nativeSearchQuery).getContent();

BoolQueryBuilder

 PageRequest 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"));

NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder)
.withPageable(pageRequest)
.withSort(idSortBuilder)
.build();
String query = nativeSearchQuery.getQuery().toString();
logger.info(query);
List<Person> content = personRepository.search(nativeSearchQuery).getContent();

IdsQueryBuilder

//    GET /person/_search
//    {
//        "query": {
//        "ids": {
//            "values": [
//            "25",
//                    "44",
//                    "126"
//      ]
//        }
//    }
//    }
PageRequest pageRequest = PageRequest.of(0, 50);
FieldSortBuilder idSortBuilder = SortBuilders.fieldSort("id").order(SortOrder.ASC);
IdsQueryBuilder idsQueryBuilder = QueryBuilders.idsQuery().addIds("25", "44", "126");
NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
.withQuery(idsQueryBuilder)
.withPageable(pageRequest)
.withSort(idSortBuilder)
.build();
String query = nativeSearchQuery.getQuery().toString();
logger.info(query);
List<Person> content = personRepository.search(nativeSearchQuery).getContent();

DisMaxQueryBuilder

//    GET /person/_search
//    {
//        "query": {
//        "dis_max": {
//            "tie_breaker": 0.7,
//                    "boost": 1.2,
//                    "queries": [
//            {
//                "term": {
//                "firstname": {
//                    "value": "Effie"
//                }
//            }
//            },
//            {
//                "match": {
//                "gender": "m"
//            }
//            }
//      ]
//        }
//    }
//    }

PageRequest pageRequest = PageRequest.of(0, 50);
FieldSortBuilder idSortBuilder = SortBuilders.fieldSort("id").order(SortOrder.ASC);

DisMaxQueryBuilder disMaxQueryBuilder = QueryBuilders.disMaxQuery()
.add(QueryBuilders.termQuery("firstname", "Effie"))
.add(QueryBuilders.matchQuery("gender", "m"))
.boost(1.2f)
.tieBreaker(0.7f);

NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
.withQuery(disMaxQueryBuilder)
.withPageable(pageRequest)
.withSort(idSortBuilder)
.build();
String query = nativeSearchQuery.getQuery().toString();
logger.info(query);
List<Person> content = personRepository.search(nativeSearchQuery).getContent();
    

FuzzyQueryBuilder

PageRequest pageRequest = PageRequest.of(0, 50);
FieldSortBuilder idSortBuilder = SortBuilders.fieldSort("id").order(SortOrder.ASC);

FuzzyQueryBuilder fuzzyQueryBuilder = QueryBuilders.fuzzyQuery("firstname", "effie");

NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder().withQuery(fuzzyQueryBuilder)
.withPageable(pageRequest)
.withSort(idSortBuilder)
.build();
String query = nativeSearchQuery.getQuery().toString();
logger.info(query);
List<Person> content = personRepository.search(nativeSearchQuery).getContent();

prefixQuery

PageRequest pageRequest = PageRequest.of(0, 50);
FieldSortBuilder idSortBuilder = SortBuilders.fieldSort("id").order(SortOrder.ASC);

PrefixQueryBuilder prefixQueryBuilder = QueryBuilders.prefixQuery("firstname", "b");
NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
.withQuery(prefixQueryBuilder)
.withPageable(pageRequest)
.withSort(idSortBuilder)
.build();
String query = nativeSearchQuery.getQuery().toString();
logger.info(query);
List<Person> content = personRepository.search(nativeSearchQuery).getContent();

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);
NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
.withQuery(rangeQueryBuilder)
.withPageable(pageRequest)
.withSort(idSortBuilder)
.build();
String query = nativeSearchQuery.getQuery().toString();
logger.info(query);
List<Person> content = personRepository.search(nativeSearchQuery).getContent();
PageRequest pageRequest = PageRequest.of(0, 50);
FieldSortBuilder idSortBuilder = SortBuilders.fieldSort("id").order(SortOrder.ASC);
//address: "398 Dearborn Court",  有3个term  查询court 结束的位置为 3
SpanFirstQueryBuilder spanFirstQueryBuilder = QueryBuilders.spanFirstQuery(QueryBuilders.spanTermQuery("address", "court"), 3);
NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder().withQuery(spanFirstQueryBuilder)
.withPageable(pageRequest)
.withSort(idSortBuilder)
.build();
String query = nativeSearchQuery.getQuery().toString();
logger.info(query);
List<Person> content = personRepository.search(nativeSearchQuery).getContent();

boolQuery

PageRequest pageRequest = PageRequest.of(0, 10);
FieldSortBuilder idSortBuilder = SortBuilders.fieldSort("id").order(SortOrder.ASC);

BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
.must(QueryBuilders.matchQuery("gender", "f"))
.should(QueryBuilders.termQuery("address", "court"))
.should(QueryBuilders.termQuery("state","md"))
.filter(QueryBuilders.rangeQuery("age").gte(30))
.filter(QueryBuilders.rangeQuery("balance").gte(2726));

NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
.withQuery(boolQueryBuilder)
.withPageable(pageRequest)
.withSort(idSortBuilder)
.build();
String query = nativeSearchQuery.getQuery().toString();
logger.info(query);
List<Person> content = personRepository.search(nativeSearchQuery).getContent();
/**
     *
     *
    GET /person/_search
    {
        "query": {
            " function_score": {
                "query": {
                    "match": {
                        "gender": "F"
                    }
                },
                "field_value_factor": {
                    "field": "balance",
                            "modifier": "log1p",
                            "factor": 0.5
                }
          , "boost_mode": "sum"
            }
        }
    }*/
    
PageRequest pageRequest = PageRequest.of(0, 10);
FieldSortBuilder idSortBuilder = SortBuilders.fieldSort("id").order(SortOrder.ASC);

//bool query
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery().must(QueryBuilders.matchQuery("gender", "F"));

//feild_value_factor
FieldValueFactorFunctionBuilder functionBuilder = ScoreFunctionBuilders.fieldValueFactorFunction("balance")
.modifier(FieldValueFactorFunction.Modifier.LOG1P)
.factor(0.5f);

FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(boolQueryBuilder, functionBuilder).boostMode(CombineFunction.SUM);

NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
.withQuery(functionScoreQueryBuilder)
.withPageable(pageRequest)
.withSort(idSortBuilder)
.build();
String query = nativeSearchQuery.getQuery().toString();
logger.info(query);
Page<Person> page = personRepository.search(nativeSearchQuery);
logger.info("page: "+page.toString());
List<Person> content = page.getContent();

functionScoreQuery

/**

     GET /person/_search
     {
         "query": {
             "function_score": {
                 "query": {
                     "match": {
                         "gender": "F"
                    }
             },
             "gauss": {
                 "balance": {
                     "origin": "43951",
                     "scale": "100",
                     "offset": "10"
                 }
             },
             "boost_mode": "sum"
             }
         }
     }
     */
PageRequest pageRequest = PageRequest.of(0, 10);
FieldSortBuilder idSortBuilder = SortBuilders.fieldSort("id").order(SortOrder.ASC);

//bool query
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery().must(QueryBuilders.matchQuery("gender", "F"));
GaussDecayFunctionBuilder gaussDecayFunctionBuilder = ScoreFunctionBuilders.gaussDecayFunction("balance", "43951", "100", "10");

//builder
FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(boolQueryBuilder, gaussDecayFunctionBuilder).boostMode(CombineFunction.SUM);

NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder().withQuery(functionScoreQueryBuilder)
.withPageable(pageRequest)
//.withSort(idSortBuilder)
.build();

String query = nativeSearchQuery.getQuery().toString();
logger.info(query);
Page<Person> page = personRepository.search(nativeSearchQuery);
logger.info("page: "+page.toString());
List<Person> content = page.getContent();
/**   function_score weight query
    GET /person/_search
    {
        "query": {
            "function_score": {
                    "query": {
                        "bool": {
                            "must": [
                            {
                                "match": {
                                "gender": "F"
                            }
                            },{
                                "range": {
                                    "age": {
                                        "gte": 25,
                                                "lte": 30
                                    }
                                }
                            }
                  ]
                        }
                    },
                    "functions": [
                    {
                        "weight": 2
                    }
                ]
            }
        }
    }
     **/
PageRequest pageRequest = PageRequest.of(0, 10);
FieldSortBuilder idSortBuilder = SortBuilders.fieldSort("id").order(SortOrder.ASC);

//bool query
BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
.must(QueryBuilders.matchQuery("gender", "F"))
.must(QueryBuilders.rangeQuery("age").gte(25).lte(30));

//weight buil
WeightBuilder weightBuilder = ScoreFunctionBuilders.weightFactorFunction(2.0f);

//builder
FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(boolQueryBuilder, weightBuilder).boostMode(CombineFunction.SUM);

NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
.withQuery(functionScoreQueryBuilder)
.withPageable(pageRequest)
//.withSort(idSortBuilder)
.build();

String query = nativeSearchQuery.getQuery().toString();
logger.info(query);
Page<Person> page = personRepository.search(nativeSearchQuery);
logger.info("page: "+page.toString());
List<Person> content = page.getContent();
반응형
반응형

엘라스틱 을 조회할떄 네이밍에 언더바(언더스코어)가 들어간 경우 일반적인 방법으로 ElasticsearchRepository 라이브러리로 조회가 가능하지 않다.

EX) name_field : '데이터'

 

 

이거 오류 해결 방법 좀 알고 싶었으나 지지고 볶아도 오류해결 방법이 없다. 

애초에 네이밍을 카멜로 했거나 그게 안되면 ElasticsearchOperations 을 사용해서 엘라스틱 조회를 해야한다.

 

간편하게 사용하기에는 아무래도 ElasticsearchRepository 가 jpa 랑 같아 사용하기 편한데, 복잡한 쿼리에는 불편한 점이 따르니 어쩔 수 없다.

굳이 언더바를 검색하려면 방법은 있다.

@Repository
public interface SampleRepository extends ElasticsearchRepository<SampleData, String> {

    @Query("{\"bool\": {\"must\": {\"match\": {\"name_field\": \"?0\"}}}}")
    List<SampleData> findByName(String name);
}

이런 식으로 네이티브 쿼리를 보내는 방법 밖에 알 수가 없다.

하지만 이렇게 할거면 굳이 ElasticsearchRepository 를 쓰는 이유가 있을까 싶다. 그냥 ElasticsearchOperations 로만 사용해도 된다.

또는 ElasticsearchRepository 에서 search 메소드에 queryBuilder 를 넣어서 ElasticsearchOperations처럼 사용해도 된다.

 

 

새로 업데이트 된 엘라스틱에서는 가능해졌는지는 모르겠지만,

내가 사용중인 버젼 spring boot 2.1.2, 

spring-data-elasticsearch:3.1.4 에서는 가능하지 않다.

 

아마 상위버젼에서도 불가 할 것이다.

jpa 에서는 @Colunm(name="name_field") 이런식으로 해결 가능한데, elastic 에는 이러한 어노테이션이 존재하지가 않아 되지 않는다.

 

구글링을 하면 @@JsonProperty("name_field") 이렇게 해결하라는 글이 하나 있는데, 동작하지 않는다. 찾아보면 다 동작이 안된다는 말이 더 많다.

 

 

처음 엘라스틱 데이터를 만들때 언더바, 언더스코어 등을 네이밍에 사용하지 말고 카멜케이스로 만들자..

 

 

참고

stackoverflow.com/questions/50528299/query-elasticsearch-using-spring-data-elasticsearch-with-fields-containing-under
반응형

+ Recent posts