Framework/Spring

[Spring] Elasticsearch에서 Query String을 활용해서 검색하기 (feat. Java) - 컴도리돌이

컴도리돌이 2024. 11. 1. 09:00
728x90

Elasticsearch에서 query_string은 사용자가 입력한 문자열을 기반으로 쿼리를 생성하는 아주 강력한 기능입니다. 이 방식은 복잡한 검색 조건을 간단하게 표현할 수 있도록 도와줍니다. 예를 들어, 사용자가 "apple"을 입력하면 "apple"과 관련된 모든 문서를 찾을 수 있는 거죠.

 

그렇다면 multi_match나 match와 같은 다른 쿼리와 비교했을 때, 왜 굳이 query_string을 사용해야 할까요? 🤔 우선, query_string은 검색어에 여러 조건을 한 번에 적용할 수 있는 유연함이 있어요. 사용자가 "apple AND banana OR orange"와 같은 복잡한 쿼리를 입력하면, 이를 해석해 다양한 조건을 적용할 수 있답니다. 반면, match나 multi_match는 주로 단일 필드에 대한 일치 검색에 국한되기 때문에 이렇게 복잡한 검색은 어려워요. (물론 multi_match는 다중 필드 대상으로 검색에 유용하긴 해요 😊)

 

또한, query_string은 와일드카드(*,?)를 사용할 수 있어 검색어에 대해 더 유연한 패턴 매칭이 가능해요. 특히 사용자가 정확한 단어를 모르거나 오타가 있을 때 이 기능이 더욱 빛을 발하죠. 사용자가 "서울특별시" 대신 "서운특별시"라고 입력했을 때도, 이를 잘 처리해 줄 수 있으니까요. 🤔

 

이제 query_string에서 제가 즐겨 사용하는 몇 가지 옵션에 대해 다뤄볼게요. 😊

먼저 allowLeadingWildcard 옵션입니다. 이 옵션은 사용자가 검색어의 맨 앞에 와일드카드(*)를 붙일 수 있게 해 줘요. 이렇게 하면 좀 더 유연하게 검색할 수 있지만 성능에 영향을 줄 수도 있어요. 예를 들어, 사용자가 "서울특별시"로 시작하지 않는 문장을 찾고 싶을 때 유용하답니다.

boolQuery.must(
    m -> m.queryString(
        qs -> qs.fields(fieldList)
                .query("*서울특별시")
                .allowLeadingWildcard(true)
    )
);

 

다음은 fuzzy 옵션입니다. 이 옵션은 오타를 허용해 줘서 사용자가 입력한 단어와 비슷한 다른 단어를 찾을 수 있게 해 줍니다. 예를 들어, 사용자가 "서운특별시"라고 입력하면 이를 "서울특별시"로 인식해 주도록 하는 거죠. 하지만 이 옵션은 항상 기대하는 만큼 오타를 잘 잡아내지는 않더라고요. 🤨

boolQuery.must(
    m -> m.queryString(
        qs -> qs.fields(fieldList)
                .query("서운특별시")
                .fuzziness("1")
    )
);

 

analyze_wildcard는 true로 설정되면 와일드카드 검색 시 Elasticsearch가 입력된 문자열을 분석해서 검색을 진행해요. 복잡한 쿼리에도 유용하지만 성능에 영향을 줄 수 있죠. 사용자가 특정 키워드로 시작하는 모든 문서를 검색하고 싶을 때 이 옵션을 활용할 수 있어요.

boolQuery.must(
    m -> m.queryString(
        qs -> qs.fields(fieldList)
                .query("서울특별시*")
                .analyzeWildcard(true)
        )
    );

 

 

auto_generate_synonyms_phrase_query 옵션은 query_string 쿼리에서 유사어를 자동으로 처리할 수 있도록 돕는 설정입니다. 이 옵션이 활성화되면, 검색어에 포함된 유사어를 기반으로 해당 필드의 연관 표현까지 확장해서 검색합니다. 예를 들어, "기흥구"로 검색하면 "구"나 "동"을 포함한 유사 표현을 함께 조회해 줄 수 있어요.

boolQuery.must(m -> m.queryString(
        qs -> qs.fields(fieldList)
                .query("기흥구")
                .autoGenerateSynonymsPhraseQuery(true)
));

 

위 코드는 전체 필드에서 "기흥구"로 검색할 때, 이와 관련된 유사어를 포함한 표현들도 자동으로 조회 범위에 넣어줍니다. 특히 주소나 지명처럼 여러 방식으로 표현될 수 있는 데이터를 검색할 때 매우 유용한데요, 이를 통해 사용자가 꼭 정확한 키워드를 입력하지 않아도 연관 결과가 반환되기 때문에 검색 경험이 향상됩니다.

 

단, 자동으로 유사어 쿼리를 생성하므로, 설정에 따라 예상보다 더 많은 결과가 반환될 수 있으며, 성능에 영향을 미칠 가능성도 있습니다.

 

근데 키바나에서는 auto_generate_phrase_queries로 잘못 자동완성 되니 주의해서 사용하셔야 합니다.🙄 

 

 

Have I found a documentation error about auto_generate_phrase_queries in query stings?

When following the documentation about query_sting and auto_generate_phrase_queries, Query string query | Elasticsearch Guide [8.11] | Elastic, is suggest that elastic 7.5 does indeed support auto_generate_phrase_queries, but when I try, I get this error {

discuss.elastic.co


Query String에서 와일드카드 정교하게 활용하기

와일드카드는 queryString의 가장 유용한 기능 중 하나로, 복잡하고 유연한 검색이 가능해지게 만듭니다. 예를 들어, 특정 필드 값의 일부 패턴만 매칭시키고 싶을 때 유용하게 사용할 수 있어요. 사용자가 위치와 용도를 조합한 검색 조건을 정교하게 입력할 때 ** 와일드카드를 활용해 매우 특정한 결과를 도출할 수 있습니다 👍

 

boolQuery.must(m -> m.queryString(
        qs -> qs.fields(List.of("addr_road"))
                .query("경기* 용?? 기흥* 동백??대로")  // 유사어, 와일드카드 적용
                .defaultOperator(Operator.And)
                .analyzeWildcard(true)
                .fuzziness("AUTO")                    // 오타 허용
));

 

우선, "addr_road" 필드에서 "경기* 용?? 기흥* 동백?? 대로"로 쿼리를 지정했는데, 와일드카드 *와?를 적절히 활용하여 포괄적으로 검색할 수 있게 했어요. 예를 들어, "경기*"는 "경기도"뿐 아니라 "경기북부"처럼 '경기'로 시작하는 단어들을 포함할 수 있어요. 그리고 용??처럼?를 사용하면 글자 수가 비슷한 용인시, 용문동 등 다양한 결과가 포함되도록 만들어주죠.

 

또 defaultOperator를 Operator.And로 설정해서, 지정한 모든 단어가 포함된 결과만 반환되도록 했어요. 이렇게 하면 경기, 용, 기흥 등의 단어 중 하나만 포함된 문서는 검색되지 않기 때문에 보다 정확한 결과를 얻을 수 있죠.

 

추가로, analyzeWildcard 옵션을 true로 설정하여 와일드카드가 포함된 검색어도 분석할 수 있도록 했어요. 이 설정 덕분에 주소 검색에서 중간에 포함된 와일드카드 문자도 효과적으로 매칭되도록 할 수 있어요.


복잡한 조건 설정을 위한 Query String 활용하기

다양한 필드를 조합해 특정 범위나 위치에 맞는 데이터를 필터링하는 방법도 존재합니다. 이 예시 코드에서 사용한 "location_area:<=300 AND location:기흥구"는 주로 숫자 범위 필터링과 특정 지역에 대한 정확한 위치 매칭을 설정하는 방식으로 활용할 수 있어요. 

boolQuery.must(m -> m.queryString(
        qs -> qs.query("(location_area:<=300) AND (location:기흥구)") 
))

 

이와 같은 조합으로 queryString 쿼리의 고도화된 설정이 가능하며, 숫자와 텍스트 필드의 결합을 통해 다소 모호한 검색도 정교하게 수행할 수 있어요. 예를 들어, "location_area:<=500 AND location:서울특별시"와 같은 조건을 추가해, 면적이 500 이하이고 위치가 서울인 데이터를 찾도록 응용할 수 있습니다.

 

query_string 쿼리는 강력하면서도 유연한 검색 조건을 설정할 수 있는 방법을 제공합니다. 이를 통해 데이터베이스에서 더 정확하고 원하는 정보를 손쉽게 검색할 수 있게 되죠. 데이터 검색은 단순한 작업이 아닐 수 있지만, 올바른 도구와 전략을 사용하면 더 수월해질 수 있습니다.


 

Query string query | Elasticsearch Guide [8.15] | Elastic

Allowing a wildcard at the beginning of a word (eg "*ing") is particularly heavy, because all terms in the index need to be examined, just in case they match. Leading wildcards can be disabled by setting allow_leading_wildcard to false.

www.elastic.co