Рубрики
Без рубрики

Настройка Spring и Postgres для полнотекстового поиска

Введение В этой статье мы создадим Pokemon API, способный выполнять полнотекстовый поиск. Тот… С тегами java, tutorial, postgres, database.

В этой статье мы создадим Pokemon API, способный выполнять полнотекстовый поиск. Это означает, что мы сможем искать Pokemon по его текстовому описанию с помощью Spring Boot и Postresql!

Самым большим преимуществом этой настройки является использование JPA (Java Persistence API) для взаимодействия с базой данных вместо непосредственного использования собственных SQL-запросов. Другими словами, когда мы запрашиваем базу данных, мы автоматически получаем объекты Java ( Entities ).

Вы можете попробовать демонстрационную версию интерфейса на CodeSandbox:

Серверный код находится на Github:

fabiothiroki/весна-покемон-текстовый поиск

Приложение spring boot, реализующее полнотекстовый поиск с использованием Postgresql

Кредиты за дизайн интерфейса принадлежат |/Florin Pop .

Перейдите в Spring Initializr , чтобы выбрать основные зависимости и загрузить шаблон нашего проекта. На момент написания этой статьи я выбрал:

  • Проект Gradle
  • Язык Java 8
  • Пружинный ботинок 2.3.1
  • Пружинная Паутина
  • Spring Data JPA

Прежде чем мы начнем эффективно кодировать, давайте сделаем шаг назад и поговорим о варианте использования полнотекстового поиска в нашем API. Предположим, я запрашиваю API для word растущий , я хочу, по крайней мере, следующих результатов:

  • Бульбазавр: В течение некоторого времени после своего рождения он растет , получая питание от семени на своей спине.
  • Нидорина: Когда он чувствует опасность, он поднимает все шипы на своем теле. Эти колючки растут медленнее, чем Нидорино.

Мы могли бы достичь этого, используя обычный SQL КАК и оператор , но нам все равно нужно было бы знать основу (или корневую форму) слова growing . Таким образом, запрос будет следующим:

SELECT * FROM Pokemon WHERE description LIKE 'grow%'

Но теперь для каждого другого английского слова, которое мы хотели бы найти, нам нужно было бы вручную сопоставить слово с соответствующей основой. Вот где нам помогает полнотекстовый поиск, чтобы мы могли выполнять запросы по любому слову.

Тот же поиск, приведенный выше, с использованием операторов полнотекстового поиска из Postgresql, является:

SELECT * FROM Pokemon 
WHERE to_tsvector(description) @@ plainto_tsquery('growing')

Как вы можете заметить, мы можем запрашивать напрямую по слову growing и получите те же результаты. В следующем разделе я объясню, что такое to_tsvector и plainto_tsquery означает.

to_tsvector

По сути, он получает строку в качестве входных данных и возвращает список лексем (минимальная значимая единица языка). Давайте проверим, каковы лексемы описания бульбасавра:

В течение некоторого времени после своего рождения он растет, получая питание из семени на спине.

SELECT to_tsvector(description) FROM pokemon where id=1
---
'back':17 'birth':6 'gain':10 'grow':8 'nourish':11 'seed':14 'time':3

Как вы можете заметить, растет слово сводится к его лексеме расти .

plainto_tsquery

Этот оператор преобразует строку в tsquery , который представляет собой список токенов и логических |/операторов, описывающих термины, которые мы хотели бы найти.

SELECT plainto_tsquery('growing')
---
'grow'

Короче говоря, мы применяем to_tsvector к столбцу базы данных, содержащему текст, который мы хотели бы сопоставить, и мы применяем plainto_tsquery при вводе в поиск.

Итак, как мы можем использовать эти классные текстовые операторы при загрузке Spring без необходимости писать собственные SQL-запросы напрямую?

Сначала мы должны объявить класс Metadata Builder Contributor для регистрации новой функции SQL:

public class SqlFunctionsMetadataBuilderContributor implements MetadataBuilderContributor {
    @Override
    public void contribute(MetadataBuilder metadataBuilder) {
        metadataBuilder.applySqlFunction("fts",
                new SQLFunctionTemplate(BooleanType.INSTANCE,
                        "to_tsvector(description) @@ plainto_tsquery(?1)"));
    }
}

Не application.properties конфигурационный файл, нам просто нужно добавить ссылку на этот класс:

spring.jpa.properties.hibernate.metadata_builder_contributor=com.example.demo.fts.SqlFunctionsMetadataBuilderContributor

Здесь мы регистрируем функцию fts , которая получает один параметр и пытается сопоставить параметр со столбцом description из таблицы Pokemon .

Теперь в классе репозитория мы можем использовать оператор fts непосредственно в JPQL:

@Repository
public interface PokemonRepository extends CrudRepository {

    @Query("SELECT p FROM Pokemon p WHERE fts(:description) = true")
    List search(@Param("description") String description);

}

Наконец, мы реализуем наш API, который получает параметр search по URL и вызывает соответствующий метод из своего репозитория:

@RestController()
@RequestMapping("/pokemon")
public class PokemonController {

  @Autowired
  private PokemonRepository repository;

  @GetMapping()
  public List findByDescription(@RequestParam String search) {
      return repository.search(search);
  }
}

Вы можете протестировать конечную точку, обратившись к http://localhost:8080/pokemon/?search=growing в вашем браузере.

Мы узнали, как мы можем использовать JPA для включения полнотекстового поиска поисковых запросов. Это может быть очень полезно при обнаружении ошибок во время компиляции, при этом получая большое преимущество в производительности во время выполнения.

Оригинал: “https://dev.to/fabiothiroki/setup-spring-and-postgres-for-full-text-search-4n97”