이번 문서 정리는 아래 링크 내용입니다!
이번에도 내용 가장 아래에 간단히 내용을 요약해 올려두겠습니다:)
https://redis.io/learn/develop/java/redis-and-spring-course/lesson_7
Redis를 사용한 검색
저자: Brian Sam-Bodden, Redis 개발자 옹호자
목적
Redis의 내장된 검색 및 쿼리 엔진을 활용하여 SQL과 NoSQL 시스템 간의 쿼리 간극을 메우는 방법을 학습합니다. 주로 두 가지 일상적인 사용 사례에 중점을 둡니다: 풀 텍스트 검색과 자동 완성.
학습 내용
- Redis를 사용하여 검색 인덱스를 생성하는 방법
- Spring Boot 애플리케이션에서 Redis를 사용하여 검색 기능을 구현하는 방법
- Redis 제안 기능을 사용하여 자동 완성을 구현하는 방법
문제 발생 시:
- 이 레슨의 진행 상황은 redi2read GitHub 저장소에서 확인할 수 있습니다.
Redis Stack 검색 및 쿼리 엔진
Redis Stack은 Redis의 소스 사용 가능 버전으로, Redis에서 쿼리, 보조 인덱싱, 풀 텍스트 검색을 수행할 수 있습니다. Redis Stack은 정렬된 세트와 같은 내부 데이터 구조를 사용하지 않고 Redis에 보조 인덱스를 구현합니다. 이를 통해 다중 필드 쿼리, 집계 및 풀 텍스트 검색과 같은 고급 기능을 제공합니다. 이러한 기능을 통해 Redis를 주 데이터베이스로 사용하여 복잡한 쿼리를 수행하고, 데이터를 업데이트 및 인덱싱하는 코드를 추가하지 않고도 데이터를 액세스할 수 있습니다.
spring-redisearch 사용하기
Spring Redis Search는 LettuSearch를 기반으로 한 라이브러리로, Spring 애플리케이션에서 Redis Stack에 접근할 수 있게 합니다. LettuSearch는 인기 있는 Redis Java 클라이언트 라이브러리 Lettuce를 기반으로 한 Redis Stack의 Java 클라이언트입니다.
spring-redisearch 의존성 추가
Maven pom.xml에 다음 의존성을 추가합니다:
<dependency>
<groupId>com.redislabs</groupId>
<artifactId>spring-redisearch</artifactId>
<version>3.0.1</version>
</dependency>
검색 인덱스 생성
인덱스를 생성하려면 인덱싱할 필드와 그 타입을 나열하는 스키마를 정의해야 합니다. Book 모델의 경우, 네 가지 필드를 인덱싱합니다:
- 제목 (Title)
- 부제목 (Subtitle)
- 설명 (Description)
- 저자 (Authors)
인덱스 생성은 FT.CREATE 명령을 사용하여 수행됩니다. 검색 인덱스를 생성하는 코드는 다음과 같습니다:
CreateBooksSearchIndex.java 생성
package com.redislabs.edu.redi2read.boot;
import com.redislabs.edu.redi2read.models.Book;
import com.redislabs.lettusearch.CreateOptions;
import com.redislabs.lettusearch.Field;
import com.redislabs.lettusearch.RediSearchCommands;
import com.redislabs.lettusearch.StatefulRediSearchConnection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import io.lettuce.core.RedisCommandExecutionException;
import lombok.extern.slf4j.Slf4j;
@Component
@Order(6)
@Slf4j
public class CreateBooksSearchIndex implements CommandLineRunner {
@Autowired
private StatefulRediSearchConnection<String, String> searchConnection;
@Value("${app.booksSearchIndexName}")
private String searchIndexName;
@Override
@SuppressWarnings({ "unchecked" })
public void run(String... args) throws Exception {
RediSearchCommands<String, String> commands = searchConnection.sync();
try {
commands.ftInfo(searchIndexName);
} catch (RedisCommandExecutionException rcee) {
if (rcee.getMessage().equals("Unknown Index name")) {
CreateOptions<String, String> options = CreateOptions.<String, String>builder()//
.prefix(String.format("%s:", Book.class.getName())).build();
Field<String> title = Field.text("title").sortable(true).build();
Field<String> subtitle = Field.text("subtitle").build();
Field<String> description = Field.text("description").build();
Field<String> author0 = Field.text("authors.[0]").build();
Field<String> author1 = Field.text("authors.[1]").build();
Field<String> author2 = Field.text("authors.[2]").build();
Field<String> author3 = Field.text("authors.[3]").build();
Field<String> author4 = Field.text("authors.[4]").build();
Field<String> author5 = Field.text("authors.[5]").build();
Field<String> author6 = Field.text("authors.[6]").build();
commands.create(
searchIndexName, //
options, //
title, subtitle, description, //
author0, author1, author2, author3, author4, author5, author6 //
);
log.info(">>>> Created Books Search Index...");
}
}
}
}
설명
StatefulRediSearchConnection을 주입하여 동기화 모드에서 검색 명령에 접근합니다.sync()메서드를 사용하여 검색 명령의 인스턴스를 얻습니다.FT.INFO명령을 사용하여 인덱스가 존재하는지 확인합니다.- 인덱스가 없으면
CreateOptions객체를 생성하고 필드 객체를 만듭니다. create메서드를 호출하여 인덱스를 생성합니다.
풀 텍스트 검색 쿼리
Redis Stack은 풀 텍스트 검색 엔진을 제공하여 강력한 쿼리를 실행할 수 있습니다. 예를 들어, "networking"과 관련된 모든 책을 검색하려면 다음 명령을 실행합니다:
127.0.0.1:6379> FT.SEARCH books-idx "networking" RETURN 1 title
이를 통해 "networking" 관련 책들의 제목을 반환합니다.
BooksController에 검색 기능 추가
검색 기능을 BooksController에 추가하려면 다음 코드를 사용합니다:
@Value("${app.booksSearchIndexName}")
private String searchIndexName;
@Autowired
private StatefulRediSearchConnection<String, String> searchConnection;
@GetMapping("/search")
public SearchResults<String,String> search(@RequestParam(name="q")String query) {
RediSearchCommands<String, String> commands = searchConnection.sync();
SearchResults<String, String> results = commands.search(searchIndexName, query);
return results;
}
자동 완성 제안 추가 및 가져오기
Redis Stack은 자동 완성 기능을 제공하여 검색 정밀도를 향상시킵니다. 자동 완성 기능을 구현하려면 다음과 같은 명령을 사용합니다:
FT.SUGADD: 자동 완성 사전에 제안 문자열 추가FT.SUGGET: 문자열에 대한 제안 목록 가져오기FT.SUGDEL: 자동 완성 사전에서 제안 문자열 삭제FT.SUGLEN: 자동 완성 사전의 크기 반환
CreateAuthorNameSuggestions.java 생성
package com.redislabs.edu.redi2read.boot;
import com.redislabs.edu.redi2read.repositories.BookRepository;
import com.redislabs.lettusearch.RediSearchCommands;
import com.redislabs.lettusearch.StatefulRediSearchConnection;
import com.redislabs.lettusearch.Suggestion;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;
@Component
@Order(7)
@Slf4j
public class CreateAuthorNameSuggestions implements CommandLineRunner {
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Autowired
private BookRepository bookRepository;
@Autowired
private StatefulRediSearchConnection<String, String> searchConnection;
@Value("${app.autoCompleteKey}")
private String autoCompleteKey;
@Override
public void run(String... args) throws Exception {
if (!redisTemplate.hasKey(autoCompleteKey)) {
RediSearchCommands<String, String> commands = searchConnection.sync();
bookRepository.findAll().forEach(book -> {
if (book.getAuthors() != null) {
book.getAuthors().forEach(author -> {
Suggestion<String> suggestion = Suggestion.builder(author).score(1d).build();
commands.sugadd(autoCompleteKey, suggestion);
});
}
});
log.info(">>>> Created Author Name Suggestions...");
}
}
}
설명
- 자동 완성 사전의 키 존재 여부를 확인하여 한 번만 실행되도록 합니다.
- BookRepository를 사용하여 모든 책을 반복하고 각 저자를 사전에 추가합니다.
컨트롤러에 자동 완성 기능 추가
자동 완성 기능을 BooksController에 추가하려면 다음 코드를 사용합니다:
@Value("${app.autoCompleteKey}")
private String autoCompleteKey;
@GetMapping("/authors")
public List<Suggestion<String>> authorAutoComplete(@RequestParam(name="q")String query) {
RediSearchCommands<String
, String> commands = searchConnection.sync();
SuggetOptions options = SuggetOptions.builder().max(20L).build();
return commands.sugget(autoCompleteKey, query, options);
}
위의 코드로 자동 완성 기능을 사용하여 저자 이름을 검색할 수 있습니다. 예를 들어, "brian s"를 입력하면 해당하는 저자 이름 제안 목록을 반환합니다.
Redis를 사용한 검색 요약
목적
Redis의 검색 및 쿼리 엔진을 활용하여 SQL과 NoSQL 시스템 간의 쿼리 간극을 메우는 방법을 학습하고, 풀 텍스트 검색과 자동 완성을 구현하는 방법을 다룹니다.
학습 내용
Redis에서 검색 인덱스 생성:
spring-redisearch와lettusearch라이브러리를 사용하여 검색 인덱스를 생성합니다.FT.CREATE명령을 사용하여 Book 모델의 제목, 부제목, 설명 및 저자 필드를 인덱싱합니다.
Spring Boot 애플리케이션에서 검색 기능 구현:
CreateBooksSearchIndex클래스를 작성하여 검색 인덱스를 생성합니다.- Redis CLI를 사용하여 인덱스가 생성되었는지 확인합니다.
풀 텍스트 검색 쿼리:
FT.SEARCH명령을 사용하여 특정 키워드가 포함된 문서를 검색합니다.- 예를 들어, "networking" 키워드를 포함하는 모든 책을 검색합니다.
- BooksController에 검색 기능을 추가하여 사용자가 쿼리 파라미터를 통해 검색할 수 있게 합니다.
자동 완성 제안 추가 및 가져오기:
- Redis Stack의 자동 완성 기능을 사용하여 사용자가 입력하는 동안 검색 결과를 안내합니다.
FT.SUGADD,FT.SUGGET,FT.SUGDEL,FT.SUGLEN명령을 사용하여 자동 완성 사전을 관리합니다.CreateAuthorNameSuggestions클래스를 작성하여 책의 저자 이름을 자동 완성 사전에 추가합니다.- BooksController에 자동 완성 기능을 추가하여 사용자가 저자 이름을 입력하면 자동 완성 제안을 제공합니다.
결론
Redis Stack의 검색 및 쿼리 엔진을 활용하여 Spring Boot 애플리케이션에서 강력한 풀 텍스트 검색과 자동 완성 기능을 구현할 수 있습니다. 이를 통해 사용자 경험을 향상시키고, 복잡한 쿼리 요구사항을 효과적으로 처리할 수 있습니다.
'Redis > Redis 개념' 카테고리의 다른 글
| Trie와 Redis ZSET 비교: 키워드 자동완성 기능에 가장 효율적인 방법은? (2) | 2024.12.17 |
|---|---|
| Redis기본 개념, 자료구조 (2) | 2024.06.12 |
| [Spring/Redis] Redis 문서 정리(User Roles, Secondary Indexes) (0) | 2024.06.11 |
| [Spring/Redis] Redis문서 정리(Object Mapping & Redis Repository) (0) | 2024.06.11 |
| [Spring/Redis] Redis문서정리(Redis Spring 시작하기) (0) | 2024.06.11 |