2 Полнотекстовый поиск
Лабораторная работа №6: Работа с JSONB и полнотекстовым поиском в PostgreSQL
Теоретические сведения
1. Тип данных JSONB
- JSONB (Binary JSON) — бинарное представление JSON, оптимизированное для хранения и запросов. Отличается от типа
JSON: - Данные хранятся в разобранном бинарном формате.
- Поддерживает индексацию (GIN, GiST).
- Удаляет пробелы и дубликаты ключей.
- Подходит для сложных структур: вложенные объекты, массивы.
- Операторы для работы с JSONB:
->: Получить значение как JSONB (например,data->'user').->>: Получить значение как текст (например,data->>'name').@>: Проверить наличие ключа или значения (например,data @> '{"age": 25}').
2. Полнотекстовый поиск
- tsvector — тип данных, хранящий лексемы текста с позициями.
- tsquery — тип данных для поисковых запросов.
- Функции:
to_tsvector('язык', текст): Преобразует текст вtsvector.to_tsquery('язык', запрос): Формирует поисковый запрос.- Оператор
@@: Проверяет соответствиеtsvectorиtsquery. - Индексы GIN:
- Оптимизируют поиск по
JSONBиtsvector. - Ускоряют операции с массивами и полнотекстовым поиском.
Примеры выполнения
1. Работа с JSONB
- Создание таблицы:
sql CREATE TABLE products ( id SERIAL PRIMARY KEY, details JSONB ); - Вставка данных:
sql INSERT INTO products (details) VALUES ('{"name": "Ноутбук", "price": 50000, "tags": ["техника", "электроника"], "specs": {"ram": 16, "cpu": "Intel"}}'), ('{"name": "Книга", "price": 300, "tags": ["литература"], "specs": {"pages": 200}}'); - Поиск по JSONB:
- Найти товары с тегом "техника":
sql SELECT * FROM products WHERE details->'tags' ? 'техника'; - Найти товары с ценой больше 40000:
sql SELECT * FROM products WHERE (details->>'price')::INT > 40000; -
Найти все книги с сраницами в количестве 300:
sql SELECT * FROM products WHERE details #>>'{space,pages}'='300'; -
Индекс для JSONB:
sql CREATE INDEX idx_gin_details ON products USING GIN (details);
2. Полнотекстовый поиск
- Создание таблицы с tsvector:
sql CREATE TABLE articles ( id SERIAL PRIMARY KEY, content TEXT, content_vector TSVECTOR GENERATED ALWAYS AS (to_tsvector('russian', content)) STORED ); - Вставка данных:
sql INSERT INTO articles (content) VALUES ('PostgreSQL — это объектно-реляционная СУБД с открытым исходным кодом.'), ('Полнотекстовый поиск позволяет искать слова и фразы в тексте.'); - Поиск по тексту:
sql SELECT * FROM articles WHERE content_vector @@ to_tsquery('russian', 'поиск & текст'); - Индекс для tsvector:
sql CREATE INDEX idx_gin_search ON articles USING GIN (content_vector);
Практические задания
Задание 1: Работа с JSONB
- Создайте таблицу
usersс полемprofileтипа JSONB. Поле должно хранить: name(строка),age(число),hobbies(массив строк),address(объект с полямиcityиstreet).- Вставьте 5 записей с разными данными.
- Напишите запросы:
- Найти пользователей, у которых в хобби есть "программирование".
- Вывести имя и город проживания для пользователей старше 25 лет.
- Создайте GIN-индекс для поля
profileи проверьте скорость поиска.
Задание 2: Полнотекстовый поиск
- Создайте таблицу
booksс полями: title(строка),description(текст),tsv(tsvector, генерируемый изdescription).- Вставьте 5 книг с описаниями (например, техническая литература, художественные произведения).
- Реализуйте поиск по словам:
- Найти все книги, где упоминается "база данных" или "алгоритм".
- Найти книги со словом "литература" в описании.
- Создайте GIN-индекс для поля
tsvи сравните скорость поиска до и после индексации.
Задание 3: Комбинирование JSONB и полнотекстового поиска
- Расширьте таблицу
products(из примера), добавив полеreviews(JSONB), которое хранит отзывы в формате:json [ {"user": "Иван", "text": "Отличный товар!", "rating": 5}, {"user": "Мария", "text": "Качество среднее", "rating": 3} ] - Напишите запрос:
- Найти товары, в отзывах которых есть слово "отличный" (используйте полнотекстовый поиск по полю
textвнутриreviews). - Дополнительно: Реализуйте поиск по рейтингу отзывов (например, товары с средним рейтингом больше 4).
Контрольные вопросы
- Чем JSONB отличается от JSON?
- Какой индекс лучше использовать для полнотекстового поиска и почему?
- Как выполнить поиск по вложенному полю в JSONB?
- Зачем нужно указывать язык в
to_tsvector?
Работа позволяет освоить гибридные возможности PostgreSQL, сочетающие реляционные и NoSQL-подходы. Примеры можно усложнить, добавив работу с массивами или более сложными запросами.