Индексы
В неймспейсах БД Reindexer предусмотрено 2 типа полей:
- индексные,
- кортежи неиндексных полей.
Каждый неймспейс может иметь до 256 одиночных индексов (1 системный псевдоиндекс tuple
и 255 пользовательских индексов). Числов композитных индексов не ограничено.
Типы индексов в Reindexer
Типы индексов, предусмотренные в Reindexer, представлены в таблице:
Тип индекса | Назначение | Особенности |
---|---|---|
hash Используется по умолчанию |
Быстрый поиск по запросам EQ и SET |
Медленная и неэффективная сортировка результатов по полю |
tree |
Быстрый поиск по запросам RANGE , GT , GE , LT и LE |
Быстрая сортировка результата по полю. По сравнению с типом hash работает немного медленнее для запросов EQ и SET |
rtree |
Используется для выполнения запросов DWithin для определения расстояния между точками (Подробнее — в разделе «Геометрические типы данных») |
Поддерживается только геометрический (географический) тип данных point ([2] float64 , reindexer.Point ) |
text |
Полнотекстовый поиск | |
ttl |
Для автоматического удаления документов/записей через заданное время | Поле может содержать только данные с типом int64 для хранения времени в UNIX-формате |
- Колоночный индекс |
Поиск полным перебором | Не может обеспечить быстрый поиск по индексной структуре, однако при использовании компараторов работает намного эффективнее, чем поля без индексов. Характеризуется наименьшим потреблением памяти по сравнению с другими типами индексов |
Также Reindexer поддерживает еще один тип индекса для полнотекстового поиска — fuzzytext
. В этом случае используется полнотекстовый движок на триграммах. Функция экспериментальная. В большинстве случаев для организации полнотекстового поиска лучше использовать индексы типа text
.
Допустимые типы значений индексных полей в Reindexer:
int
,int64
,double
,string
,bool
,composite
,point
([2]float64
,reindexer.Point
),uuid
.
Допустимые сочетания типов индексов и типов значений индексных полей в Reindexer
В Reindexer допускаются сочетания типов индексов и типов значений индексных полей согласно таблице (+
на пересечении означает допустимую комбинацию):
Тип индекса/тип значения индексного поля | hash |
tree |
rtree |
text |
ttl |
- |
---|---|---|---|---|---|---|
int |
+ | + | + | |||
int64 |
+ | + | + | + | ||
double |
+ | + | ||||
string |
+ | + | + | + | ||
bool |
+ | |||||
composite |
+ | + | + | |||
point |
+ | |||||
uuid |
+ | + |
Параметры индексных полей
Описание значений параметров индексных полей в Reindexer представлены в таблице:
Параметр | Описание/значение | Особенности |
---|---|---|
pk |
Поле — часть первичного индекса | В каждом неймспейсе должно быть хотя бы одно поле с параметром pk |
composite |
Создание композитного (составного) индекса. Перед созданием композитного индекса для всех полей из его состава требуется создать собственные индексы (любого типа, например - ). Для полтонекстовых композитных индексов это условие не является обязательным, но позволит ускорить загрузку данных с диска и пересоздание индекса |
При взаимодействии с Reindexer через Go тип поля должен быть обозначен пустой структурой: struct{} (пример) |
joined |
Joined-поле | Поле с этим тэгом используется для хранения документов, полученных в результате join’a к текущему документу (SubitemType), и обращения к ним. При взаимодействии с Reindexer через Go поле должно иметь тип []*SubitemType (пример) |
dense |
Уменьшение размера памяти, занимаемого индексным полем | Параметр полезно использовать для индексных полей с высокой селективностью. Экономия памяти составляет: * для полей, помеченных индексом типа hash и tree — 8 байт для каждого уникального значения ключа, * для полей, помеченных колоночным (- ) индексом — 4-8 байт на каждый элемент. Уменьшение объема памяти сопровождается снижением производительности. Для низкоселективных индексов типа hash и tree может существенно снизиться скорость обновления. Также из-за недостатков оптимизации кеша центрального процессора этот параметр замедляет поиск при полном сканировании в колоночных индексах - |
sparse |
Строка (документ) содержит значение индекса Sparse только в том случае, если он задан специально - нет пустых (или по умолчанию) записей этого типа индексов в строке (документе) |
Позволяет экономить оперативную память, но в то же время может снизиться производительность по сравнению с использованием обычных индексов |
collate_numeric |
Устанавливает режим сравнения строк как чисел (порядок при обычном сравнении строк: 1 , 10 , 2 ; порядок при сравнении строк как чисел: 1 , 2 , 10 ) |
Значение индексного поля должно быть задано в строковом формате |
collate_ascii |
Создает нечувствительный к регистру строковый индекс в ASCII-кодировке | Значение индексного поля должно быть задано в строковом формате |
collate_utf8 |
Создает нечувствительный к регистру строковый индекс в кодировке UTF-8 | Значение индексного поля должно быть задано в строковом формате |
collate_custom=<ORDER> |
Пользовательский порядок сортировки (задается последовательностью символов <ORDER> ). Сначала сортировка выполняется в соответствии с заданным правилом, затем — в обычном порядке (пример) |
Значение индексного поля должно быть задано в строковом формате |
linear , quadratic , greene или rstar |
Задает алгоритм построения индекса типа rtree |
Значение по умолчанию — rstar |
appendable |
Создает array-индекс из нескольких полей (в том числе из полей основной и вложенной структур) | Параметр доступен только для Go -коннектора. appendable можно использовать для двух массивов: при поиске по индексу с этим параметром они будут рассматриваться как один массив |
Добавление индексов
При добавлении некоторых типов индексов им можно задать несколько
jsonpath
. Массивjsonpath
определяет, из каких JSON-полей документа будут взяты значения для индексирования. Если у индекса несколькоjsonpath
, то проиндексированы будут все указанныеjsonpath
, встретившиеся в документе. Возможность использования несколькихjsonpath
предусмотрена для композитных и array-индексов. Если вам нужно создать одиночный индекс с несколькимиjsonpath
, используйте array-индекс ("is_array": true
).
Ниже представлены примеры создания индексов при взаимодействии с Reindexer по HTTP и через Go:
Пример добавления индекса через AddIndex на Go:
db.AddIndex("items", reindexer.IndexDef{
Name: "id", // Имя индекса
JSONPaths: []string{"id"}, // Имя индекса в JSON-структуре
IndexType: "text", // Тип индекса
FieldType: "string", // Тип значения индексного поля
})
Чтобы добавить индекс при объявлении структуры, нужно пометить индексное поле тегом reindex
.
Тег reindex
содержит имя индекса (name
), его тип (type
) и параметры/опции (opts
):
reindex:"<name>[[,<type>],<opts>]"
Пример объявлении структуры тегами reindex
через Go:
type Item struct {
ID int64 `reindex:"id,,pk"` // Добавление индекса `id`, являющегося частью первичного ключа
Name string `reindex:"name"` // Добавление индекса `name`
Articles []int `reindex:"articles"` // Добавление индекса `articles`
Year int `reindex:"year,tree"` // Добавление индекса `year`. Параметр tree обеспечивает быстрый поиск по запросам RANGE, GT и LT
}
db := reindexer.NewReindex("builtin:///tmp/reindex/testdb") // Подключение к базе данных
db.OpenNamespace("items", reindexer.DefaultNamespaceOptions(), Item{}) // Создание нового неймспейса и добавление индексов
В теле запроса для добавления индекса по HTTP указывается его тип и параметры индексного поля.
curl --location --request POST 'http://127.0.0.1:9088/api/v1/db/testdb/namespaces/items3/indexes' \
--header 'Content-Type: application/json' \
--data-raw '{
"name": "id3",
"json_paths": [
"id3"
],
"field_type": "string",
"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
}
]
}
}'
Изменение и удаление индексов
Изменение индекса
Изменение индекса происходит в два этапа: его удаление (Drop) и добавление в неймспейс с новыми значениями (Add). Поэтому при изменении индекса следует заполнять IndexDef целиком а не его отдельные поля. В противном случае опции индексного поля будут установлены в дефолтные значения.
Ниже представлены примеры создания неймспейсов при взаимодействии с базой данных через Go и по HTTP.
db.UpdateIndex("items", reindexer.IndexDef{
Name: "year", // Поиск индекса по имени
JSONPaths: []string{"Date_year"}, // Изменение имени индекса в JSON-структуре
IndexType: "tree", // Изменение типа индекса
FieldType: "int", // Изменение типа значения индексного поля
})
curl --location --request PUT 'http://127.0.0.1:9088/api/v1/db/testdb/namespaces/items3/indexes' \
--header 'Content-Type: text/plain' \
--data-raw '{
"name": "id",
"json_paths": [
"New_id"
],
"field_type": "int64",
"index_type": "tree",
"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
}
]
}
}'
Удаление индекса
Примеры команд для удаления индекса по HTTP и через Go:
db.DropIndex("items", "articles")
curl --location --request DELETE 'http://127.0.0.1:9088/api/v1/db/dbtest/namespaces/items/indexes/year'
Получение информации об индексах, доступных для неймспейса
Ниже представлен пример команды для получения списка индексов, доступных для неймспейса, по HTTP:
curl -X GET --header 'Accept: application/json' 'http://127.0.0.1:9088/api/v1/db/dbtest/namespaces/items/indexes'
Вложенные структуры
По умолчанию Reindexer сканирует все вложенные структуры и добавляет их поля (а также указатели) в неймспейс.
Пример:
type Actor struct {
Name string `reindex:"actor_name"`
}
type BaseItem struct {
ID int64 `reindex:"id,hash,pk"`
}
type ComplexItem struct {
BaseItem // Индексные поля BaseItem будут добавлены в текущую структуру
Actor []Actor // Индексные поля Actor будут добавлены в текущую структуру в виде массива
Name string `reindex:"name"` // Добавление индекса `name`
Year int `reindex:"year,tree"` // Добавление индекса `year`, обеспечивающего быстрый поиск по запросам RANGE, GT и LT
parent *Item `reindex:"-"` // Индексные поля parent не будут добавлены в структуру
}
Примеры объявления структур с индексными полями с указанием параметров на Go
Ниже представлены примеры объявления структур с индексными полями разных типов с указанием параметров на Go.
Пример 1
type Item struct {
ID int64 `reindex:"id,,pk"` // Добавление индекса `id`, являющегося частью первичного ключа (о чем говорит параметр `pk`)
Rating int `reindex:"rating"` // Добавление индекса `rating`
Year int `reindex:"year"` // Добавление индекса `year`
_ struct{} `reindex:"rating+year,tree,composite"` // Композитный индекс с сортировкой по полям `rating` и `year`
}
Пример 2
type Actor struct {
ID int `reindex:"id"` // Добавление индекса `id`
Name string `reindex:"name,tree"` // Добавление tree-индекса `name`
IsVisible bool `reindex:"is_visible,-"` // Добавление колоночного индекса `is_visible`
Metainfo int `json:"-"` // Поле "MetaInfo" не будет сохранено в reindexer
}
type ItemWithJoin struct {
ID int `reindex:"id,tree,pk"` // Добавление tree-индекса `id`, являющегося первичным ключом (о чем говорит параметр `pk`)
Name string `reindex:"name"` // Добавление индекса `name`
ActorsIDs []int `reindex:"actors_ids"` // Добавление индекса `actors_ids`
ActorsNames []int `reindex:"actors_names"` // Добавление индекса `actors_names`
Actors []*Actor `reindex:"actors,,joined"` // Joined-поле с индексом `actors`
}
Пример 3
type SortModeCustomItem struct {
ID int `reindex:"id,,pk"` // Добавление hash-индекса `id`, являющегося первичным ключом
InsItem string `reindex:"item_custom,hash,collate_custom=a-zA-Z0-9"` // Индекс типа `hash`, обеспечивающий быстрый поиск по запросам `EQ` и `SET`. Задан пользовательский порядок сортировки.
}