이번 문서 정리는 아래 링크 내용입니다!
이번에도 내용 가장 아래에 간단히 내용을 요약해 올려두겠습니다:)
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기본 개념, 자료구조 (1) | 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 |