Базовые операции с базами данных и неймспейсами

В этом разделе рассматриваются базовые операции по работе с базами данных и неймспейсами при взаимодействии с Reindexer разными способами.

Операции с базами данных

Создание базы данных. Подключение к БД

Ниже представлены примеры создания БД при взаимодействии с Reindexer через Go и по HTTP.

Фрагмент простой программы на Go, выполняющей подключение к серверу Reindexer и создание БД с именем testdb, будет выглядеть так (см. пояснения в комментариях в коде):

package main

// Импорт необходимых пакетов
import (
	"fmt"
	"math/rand"

	"github.com/restream/reindexer"
// Выбор способа подключения к Reindexer, в зависимости от варианта использования СУБД:
// Выберите этот вариант, если Reindexer встраивается в приложение, которое он обслуживает, как статическая библиотека (`Built-in`, `Embedded`).
	_ "github.com/restream/reindexer/bindings/builtin"

// Выберите этот вариант, если Reindexer встраивается в приложение как статическая библиотека с возможностью подключения других приложений-клиентов по сети (`Built-in server`):
  // _ "github.com/restream/reindexer/bindings/builtinserver"
  // "github.com/restream/reindexer/bindings/builtinserver/config"

)

func main() {
// Инициализация базы данных и подключение к ней (для варианта использования Reindexer `Builtin`)
	db := reindexer.NewReindex("builtin:///tmp/reindex/testdb")

// Инициализация базы данных и подключение к ней (для варианта использования Reindexer `Standalone`)
// База данных должна быть создана явно через Reindexer_tool или через опцию WithCreateDBIfMissing:
// Если включен режим безопасности сервера (security, --security), имя пользователя и пароль являются обязательными
  // db := reindexer.NewReindex("cproto://user:pass@127.0.0.1:6534/testdb", reindexer.WithCreateDBIfMissing())

// Инициализация базы данных и подключение к ней (для варианта использования Reindexer `Built-in server`)
  // serverConfig := config.DefaultServerConfig ()
// Если включен режим безопасности сервера (security, --security), имя пользователя и пароль являются обязательными
  // db := reindexer.NewReindex("builtinserver://user:pass@testdb",reindexer.WithServerConfig(100*time.Second, serverConfig))

// Ваш код для работы с базой данных
	
}

Пример команды для создания новой БД newdb по HTTP:

curl --location --request POST 'http://127.0.0.1:9088/api/v1/db' \
--header 'Content-Type: application/json' \
--data-raw '{
  "name": "newdb"
}'

Удаление базы данных

Пример команды для удаления базы данных testdb по HTTP:

curl --location --request DELETE 'http://127.0.0.1:9088/api/v1/db/testdb'

Рекомендованный способ удаления базы данных — напрямую через файловую систему, когда нет активных подключений к этой БД.

Операции с неймспейсами

Создание неймспейса, подключение к неймспейсу, добавление индексов

Ниже представлены примеры создания неймспейса при взаимодействии с базой данных через Go и по HTTP.

Для создания нового неймспейса с именем items воспользуйтесь функцией OpenNamespace:

// Объявление структуры с индексными полями
type Item struct {
	ID       int64  `reindex:"id,,pk"`    // Поле 'id' — первичный ключ
	Name     string `reindex:"name"`      // Текстовое индексное поле
	Articles []int  `reindex:"articles"`  // Массив 'articles' — множество записей (документов, статей) в составе индекса
	Year     int    `reindex:"year,tree"` // Добавление сортируемого индекса по полю 'year'
}

// Создание нового неймспейса
db.OpenNamespace("items", reindexer.DefaultNamespaceOptions(), Item{})

При отсутствии в БД неймспейса с указанным именем он будет добавлен, после чего произойдет подключение к нему. При наличии неймспейса items в базе данных будет создано подключение к нему. Также будут созданы индексы и задана JSON-схема в соответствии со структурой Item.

Пример запроса для создания в БД testdb нового неймспейса name с добавлением в него индекса id по HTTP:

curl --location --request POST 'http://127.0.0.1:9088/api/v1/db/testdb/namespaces' \
--header 'Content-Type: application/json' \
--data-raw '{
  "name": "name",
  "storage": {
    "enabled": true
  },
  "indexes": [
    {
      "name": "id",
      "field_type": "int64",
      "index_type": "hash",
      "is_pk": true,
      "is_array": false,
      "is_dense": false,
      "is_sparse": false,
      "collate_mode": "none",
      "sort_order_letters": "",
      "expire_after": 0,
      "config": {},
      "json_paths": [
        "id"
      ]
    }
  ],
  "temporary": false,
  "schema": "{}"
}'

Пример команды для добавления в неймспейс name базы данных testdb нового индекса year:

curl --location --request POST 'http://127.0.0.1:9088/api/v1/db/testdb/namespaces/name/indexes' \
--header 'Content-Type: application/json' \
--data-raw '{
  "name": "year",
  "json_paths": [
    "year"
  ],
  "field_type": "int",
  "index_type": "hash",
  "expire_after": 0,
  "is_pk": false,
  "is_array": false,
  "is_dense": false,
  "is_sparse": false,
  "rtree_type": "linear",
  "is_simple_tag": false,
  "collate_mode": "none",
  "sort_order_letters": "",
  "config": {
    "enable_translit": true,
    "enable_numbers_search": false,
    "enable_warmup_on_ns_copy": false,
    "enable_kb_layout": true,
    "log_level": 0,
    "merge_limit": 20000,
    "extra_word_symbols": "-/+",
    "stop_words": [
      "string"
    ],
    "stemmers": [
      "en",
      "ru"
    ],
    "synonyms": [
      {
        "tokens": [
          "string"
        ],
        "alternatives": [
          "string"
        ]
      }
    ],
    "bm25_boost": 1,
    "bm25_weight": 0.1,
    "distance_boost": 1,
    "distance_weight": 0.5,
    "term_len_boost": 1,
    "term_len_weight": 0.3,
    "position_boost": 1,
    "position_weight": 0.1,
    "full_match_boost": 1.1,
    "partial_match_decrease": 15,
    "min_relevancy": 0.05,
    "max_typos": 2,
    "max_typo_len": 15,
    "max_rebuild_steps": 50,
    "max_step_size": 4000,
    "sum_ranks_by_fields_ratio": 0,
    "fields": [
      {
        "field_name": "string",
        "bm25_boost": 1,
        "bm25_weight": 0.1,
        "term_len_boost": 1,
        "term_len_weight": 0.3,
        "position_boost": 1,
        "position_weight": 0.1
      }
    ]
  }
}'

Переименование неймспейса

Ниже представлены примеры команд для переименования неймспейса при взаимодействии с базой данных через Go и по HTTP.

Пример команды для изменения имени неймспейса c items на newitems на Go:

db.RenameNamespace("items", "newitems")

Пример команды для изменения имени неймспейса c items на newitems по HTTP:

curl --location --request GET 'http://127.0.0.1:9088/api/v1/db/testdb/namespaces/items/rename/newitems'

Удаление неймспейса

Операция полностью удаляет неймспейс из памяти и с диска, включая индексы и метаданные.

Ниже представлены примеры команд для удаления неймспейса при взаимодействии с базой данных через Go и по HTTP.

Пример команды для удаления неймспейса items из базы данных testdb на Go:

db.DropNamespace("items")

Пример команды для удаления неймспейса items из базы данных testdb по HTTP:

curl --location --request DELETE 'http://127.0.0.1:9088/api/v1/db/testdb/namespaces/items'

Операции с документами (записями) в неймспейсе

Выбор одной записи из неймспейса

Ниже представлены примеры команд для выбора одной записи из неймспейса при взаимодействии с базой данных через Go и по HTTP.

Пример команды на Go для выбора одной записи из неймспейса items с id = 40:

elem, found := db.Query("items").
		Where("id", reindexer.EQ, 40).
		Get()

Пример команды для выбора записи с id = 40 из неймспейса items по HTTP:

curl --location --request GET 'http://127.0.0.1:9088/api/v1/db/testdb/namespaces/items/items?filter=id%3D40'

Добавление новой записи в неймспейс

Для добавления записей предусмотрено 2 метода: Insert и Upsert. При использовании Insert запись добавляется, только если в неймспейсе не было записи с таким же первичным ключом. Upsert либо вставляет запись, либо обновляет существующую.

Примеры добавления записи в неймспейс:

db.Insert("items", &Item{
		ID:       1,
		Name:     "Article",
		Articles: []int{1, 2},
		Year:     2022,
	})

Команда из примера добавляет в неймспейс items новую запись с первичным ключом ID = 1, name = Article, массив Articles заполняется значениями 1 и 2, значение поля Year = 2022. Если запись с ID = 1 уже есть в неймспейсе, никаких изменений с ней не произойдет.

db.Upsert("items", &Item{
		ID:       1,
		Name:     "Article",
		Articles: []int{1, 2},
		Year:     2022,
	})

Команда из примера добавляет в неймспейс items новую запись с первичным ключом ID = 1, name = Article, массив Articles заполняется значениями 1 и 2, значение поля Year = 2022. Если запись с ID = 1 уже есть в неймспейсе, она обновится.

Для реализации вставки Insert используется POST-метод HTTP REST API:

curl --location --request POST 'http://127.0.0.1:9088/api/v1/db/testdb/namespaces/items/items' \
--header 'Content-Type: application/json' \
--data-raw '{
  "ID": 5,
  "Name": "New_Article",
  "Articles": 0,
  "Year": 2022
}'

Команда из примера добавляет в неймспейс items новую запись с первичным ключом ID = 5, name = New_Article, массив Articles остается пустым, значение поля Year = 2022. Если запись с ID = 1 уже есть в неймспейсе, никаких изменений с ней не произойдет.

Для реализации вставки Upsert используется PATCH-метод HTTP REST API:

curl --location --request PATCH 'http://127.0.0.1:9088/api/v1/db/testdb/namespaces/items/items' \
--header 'Content-Type: application/json' \
--data-raw '{
  "ID": 5,
  "Name": "New_Article2",
  "Articles": 0,
  "Year": 2023
}'

Команда из примера добавляет в неймспейс items новую запись с первичным ключом ID = 5. Если запись с таким ID уже есть в неймспейсе, произойдет ее обновление. При отсутствии записи с таким id в неймспейсе она будет добавлена.

Обновление/изменение записи

Ниже представлены примеры команд для изменения записи из неймспейса при взаимодействии с базой данных через Go и по HTTP.

Пример команды на Go для обновления записи с ID = 6 (изменение значения поля Name на New_name) из неймспейса newitems:

db.Update("newitems", &Item{
		ID:   6,
		Name: "New_name",
	})

Пример команды для обновления записи (изменение значения поля name на New_name) с первичным ключом ID = 6 из неймспейса newitems по HTTP:

curl --location --request PUT 'http://127.0.0.1:9088/api/v1/db/testdb/namespaces/newitems/items' \
--header 'Content-Type: application/json' \
--data-raw '{
  "ID": 6,
  "name": "New_name",
  "Articles": 0,
  "Year": 2022
}'

При использовании этой команды запись полностью перезаписывается. Поэтому она должна передаваться в тело запроса полностью, как объект JSON , включая значение полей, которые не будут меняться (в противном случае они будут удалены).

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

Использование прецептов при добавлении и обновлении записей

Reindexer поддерживает атомарные функции, выполнение которых происходит при условии блокировки неймспейса. Это гарантирует согласованность данных.

В Insert, Upsert и Update запросах вы можете использовать функции:

  • serial() — реализуется с помощью механизма последовательностей целых чисел. Будет полезной для автоматического увеличения значения полей с автоинкрементом.
  • now() — текущая отметка времени. Может принимать один из следующих аргументов: msec, usec, nsec или sec (используется по умолчанию).

Примеры:


// генерация значения поля id с помощью функции serial()
db.Insert ("items",&item,"id=serial()")

// добавление текущей отметки времени в наносекундах в поле updated_at при обновлении записи
db.Update ("items",&item,"updated_at=now(NSEC)")

// генерация значения поля id с помощью функции serial() и добавление текущей отметки времени в наносекундах в поле updated_at
db.Upsert ("items",&item,"updated_at=now(NSEC)","id=serial()")

Удаление записи из неймспейса

Ниже представлены примеры команд для удаления записи из неймспейса при взаимодействии с базой данных через Go и по HTTP.

Пример команды на Go для удаления записи с первичным ключом ID = 1 из неймспейса newitems:

db.Delete("newitems", &Item{
		ID: 1})

Пример команды для удаления записи с первичным ключом ID = 5 из неймспейса newitems по HTTP:

curl --location --request DELETE 'http://127.0.0.1:9088/api/v1/db/testdb/namespaces/newitems/items' \
--header 'Content-Type: application/json' \
--data-raw '{"ID":5}
'

Если нужно одной командой удалить несколько записей, первичный ключ каждой из них должен передаваться в тело запроса как отдельный JSON-объект. Пример:

curl --location --request DELETE 'http://127.0.0.1:9088/api/v1/db/testdb/namespaces/newitems/items' \
--header 'Content-Type: application/json' \
--data-raw '{"ID":3}
{"ID":4}
'