Если вы ищете информацию о добавлении документов в обычную таблицу, обратитесь к разделу добавления данных из внешних хранилищ.
Добавление документов в реальном времени поддерживается только для таблиц Real-Time и Percolate. Соответствующая SQL-команда, HTTP-эндпоинт или функции клиента вставляют новые строки (документы) в таблицу с предоставленными значениями полей. Не обязательно, чтобы таблица существовала перед добавлением документов в неё. Если таблица не существует, Manticore попытается создать её автоматически. Для получения дополнительной информации см. Автосхема.
Вы можете вставить один или несколько документов со значениями для всех полей таблицы или только для их части. В этом случае остальные поля будут заполнены значениями по умолчанию (0 для скалярных типов, пустая строка для текстовых типов).
Выражения в настоящее время не поддерживаются в INSERT, поэтому значения должны быть указаны явно.
Поле/значение ID может быть опущено, так как таблицы RT и PQ поддерживают функциональность автоматического ID. Вы также можете использовать 0 в качестве значения id для принудительной генерации автоматического ID. Строки с дублирующимися ID не будут перезаписаны с помощью INSERT. Вместо этого вы можете использовать REPLACE для этой цели.
При использовании HTTP JSON протокола у вас есть два различных формата запроса на выбор: общий формат Manticore и Elasticsearch-подобный формат. Оба формата демонстрируются в примерах ниже.
Кроме того, при использовании формата запроса Manticore JSON помните, что узел doc обязателен, и все значения должны быть предоставлены внутри него.
- SQL
- JSON
- Elasticsearch
- PHP
- Python
- Python-asyncio
- Javascript
- Java
- C#
- Rust
Общий синтаксис:
INSERT INTO <table name> [(column, ...)]
VALUES (value, ...)
[, (...)]INSERT INTO products(title,price) VALUES ('Crossbody Bag with Tassel', 19.85);
INSERT INTO products(title) VALUES ('Crossbody Bag with Tassel');
INSERT INTO products VALUES (0,'Yellow bag', 4.95);POST /insert
{
"table":"products",
"id":1,
"doc":
{
"title" : "Crossbody Bag with Tassel",
"price" : 19.85
}
}
POST /insert
{
"table":"products",
"id":2,
"doc":
{
"title" : "Crossbody Bag with Tassel"
}
}
POST /insert
{
"table":"products",
"id":0,
"doc":
{
"title" : "Yellow bag"
}
}ПРИМЕЧАНИЕ:
_createтребует Manticore Buddy. Если это не работает, убедитесь, что Buddy установлен.
POST /products/_create/3
{
"title": "Yellow Bag with Tassel",
"price": 19.85
}
POST /products/_create/
{
"title": "Red Bag with Tassel",
"price": 19.85
}$index->addDocuments([
['id' => 1, 'title' => 'Crossbody Bag with Tassel', 'price' => 19.85]
]);
$index->addDocuments([
['id' => 2, 'title' => 'Crossbody Bag with Tassel']
]);
$index->addDocuments([
['id' => 0, 'title' => 'Yellow bag']
]);indexApi.insert({"table" : "test", "id" : 1, "doc" : {"title" : "Crossbody Bag with Tassel", "price" : 19.85}})
indexApi.insert({"table" : "test", "id" : 2, "doc" : {"title" : "Crossbody Bag with Tassel"}})
indexApi.insert({"table" : "test", "id" : 0, "doc" : {{"title" : "Yellow bag"}})await indexApi.insert({"table" : "test", "id" : 1, "doc" : {"title" : "Crossbody Bag with Tassel", "price" : 19.85}})
await indexApi.insert({"table" : "test", "id" : 2, "doc" : {"title" : "Crossbody Bag with Tassel"}})
await indexApi.insert({"table" : "test", "id" : 0, "doc" : {{"title" : "Yellow bag"}})res = await indexApi.insert({"table" : "test", "id" : 1, "doc" : {"title" : "Crossbody Bag with Tassel", "price" : 19.85}});
res = await indexApi.insert({"table" : "test", "id" : 2, "doc" : {"title" : "Crossbody Bag with Tassel"}});
res = await indexApi.insert({"table" : "test", "id" : 0, "doc" : {{"title" : "Yellow bag"}});InsertDocumentRequest newdoc = new InsertDocumentRequest();
HashMap<String,Object> doc = new HashMap<String,Object>(){{
put("title","Crossbody Bag with Tassel");
put("price",19.85);
}};
newdoc.index("products").id(1L).setDoc(doc);
sqlresult = indexApi.insert(newdoc);
newdoc = new InsertDocumentRequest();
HashMap<String,Object> doc = new HashMap<String,Object>(){{
put("title","Crossbody Bag with Tassel");
}};
newdoc.index("products").id(2L).setDoc(doc);
sqlresult = indexApi.insert(newdoc);
newdoc = new InsertDocumentRequest();
HashMap<String,Object> doc = new HashMap<String,Object>(){{
put("title","Yellow bag");
}};
newdoc.index("products").id(0L).setDoc(doc);
sqlresult = indexApi.insert(newdoc);Dictionary<string, Object> doc = new Dictionary<string, Object>();
doc.Add("title", "Crossbody Bag with Tassel");
doc.Add("price", 19.85);
InsertDocumentRequest newdoc = new InsertDocumentRequest(index: "products", id: 1, doc: doc);
var sqlresult = indexApi.Insert(newdoc);
doc = new Dictionary<string, Object>();
doc.Add("title", "Crossbody Bag with Tassel");
newdoc = new InsertDocumentRequest(index: "products", id: 2, doc: doc);
sqlresult = indexApi.Insert(newdoc);
doc = new Dictionary<string, Object>();
doc.Add("title", "Yellow bag");
newdoc = new InsertDocumentRequest(index: "products", id: 0, doc: doc);
sqlresult = indexApi.Insert(newdoc);let mut doc = HashMap::new();
doc.insert("title".to_string(), serde_json::json!("Crossbody Bag with Tassel"));
doc.insert("price".to_string(), serde_json::json!(19.85));
let mut insert_req = InsertDocumentRequest {
table: serde_json::json!("products"),
doc: serde_json::json!(doc),
id: serde_json::json!(1),
..Default::default(),
};
let mut insert_res = index_api.insert(insert_req).await;
doc = HashMap::new();
doc.insert("title".to_string(), serde_json::json!("Crossbody Bag with Tassel"));
insert_req = InsertDocumentRequest {
table: serde_json::json!("products"),
doc: serde_json::json!(doc),
id: serde_json::json!(2),
..Default::default(),
};
insert_res = index_api.insert(insert_req).await;
doc = HashMap::new();
doc.insert("title".to_string(), serde_json::json!("Tellow bag"));
insert_req = InsertDocumentRequest {
table: serde_json::json!("products"),
doc: serde_json::json!(doc),
id: serde_json::json!(0),
..Default::default(),
};
insert_res = index_api.insert(insert_req).await;Query OK, 1 rows affected (0.00 sec)
Query OK, 1 rows affected (0.00 sec)
Query OK, 1 rows affected (0.00 sec){
"table": "products",
"_id": 1,
"created": true,
"result": "created",
"status": 201
}
{
"table": "products",
"_id": 2,
"created": true,
"result": "created",
"status": 201
}
{
"table": "products",
"_id": 1657860156022587406,
"created": true,
"result": "created",
"status": 201
}{
"_id":3,
"table":"products",
"_primary_term":1,
"_seq_no":0,
"_shards":{
"failed":0,
"successful":1,
"total":1
},
"_type":"_doc",
"_version":1,
"result":"updated"
}
{
"_id":2235747273424240642,
"table":"products",
"_primary_term":1,
"_seq_no":0,
"_shards":{
"failed":0,
"successful":1,
"total":1
},
"_type":"_doc",
"_version":1,
"result":"updated"
}ПРИМЕЧАНИЕ: Автосхема требует Manticore Buddy. Если это не работает, убедитесь, что Buddy установлен.
Manticore имеет механизм автоматического создания таблиц, который активируется, когда указанная таблица в запросе на вставку ещё не существует. Этот механизм включён по умолчанию. Чтобы отключить его, установите auto_schema = 0 в разделе Searchd конфигурационного файла Manticore.
По умолчанию все текстовые значения в предложении VALUES считаются имеющими тип text, за исключением значений, представляющих действительные адреса электронной почты, которые обрабатываются как тип string.
Если вы попытаетесь вставить несколько строк с разными, несовместимыми типами значений для одного и того же поля, автоматическое создание таблицы будет отменено, и будет возвращено сообщение об ошибке. Однако, если разные типы значений совместимы, результирующий тип поля будет таким, который вмещает все значения. Некоторые автоматические преобразования типов данных, которые могут произойти, включают:
- mva -> mva64
- uint -> bigint -> float (это может привести к некоторой потере точности)
- string -> text
Механизм автосхемы не поддерживает создание таблиц с векторными полями (полями типа float_vector), используемыми для поиска сходства KNN (K-ближайших соседей). Чтобы использовать векторные поля в вашей таблице, вы должны явно создать таблицу со схемой, определяющей эти поля. Если вам нужно хранить векторные данные в обычной таблице без возможности поиска KNN, вы можете хранить их как JSON-массив, используя стандартный синтаксис JSON, например: INSERT INTO table_name (vector_field) VALUES ('[1.0, 2.0, 3.0]').
Также следующие форматы дат будут распознаны и преобразованы в метки времени, в то время как все остальные форматы дат будут обрабатываться как строки:
%Y-%m-%dT%H:%M:%E*S%Z%Y-%m-%d'T'%H:%M:%S%Z%Y-%m-%dT%H:%M:%E*S%Y-%m-%dT%H:%M:%s%Y-%m-%dT%H:%M%Y-%m-%dT%H
Имейте в виду, что HTTP-эндпоинт /bulk не поддерживает автоматическое создание таблиц (автосхему). Только HTTP-эндпоинт /_bulk (Elasticsearch-подобный) и SQL-интерфейс поддерживают эту функцию.
- SQL
- JSON
MySQL [(none)]> drop table if exists t; insert into t(i,f,t,s,j,b,m,mb) values(123,1.2,'text here','test@mail.com','{"a": 123}',1099511627776,(1,2),(1099511627776,1099511627777)); desc t; select * from t;POST /insert -d
{
"table":"t",
"id": 2,
"doc":
{
"i" : 123,
"f" : 1.23,
"t": "text here",
"s": "test@mail.com",
"j": {"a": 123},
"b": 1099511627776,
"m": [1,2],
"mb": [1099511627776,1099511627777]
}
}--------------
drop table if exists t
--------------
Query OK, 0 rows affected (0.42 sec)
--------------
insert into t(i,f,t,j,b,m,mb) values(123,1.2,'text here','{"a": 123}',1099511627776,(1,2),(1099511627776,1099511627777))
--------------
Query OK, 1 row affected (0.00 sec)
--------------
desc t
--------------
+-------+--------+----------------+
| Field | Type | Properties |
+-------+--------+----------------+
| id | bigint | |
| t | text | indexed stored |
| s | string | |
| j | json | |
| i | uint | |
| b | bigint | |
| f | float | |
| m | mva | |
| mb | mva64 | |
+-------+--------+----------------+
8 rows in set (0.00 sec)
--------------
select * from t
--------------
+---------------------+------+---------------+----------+------+-----------------------------+-----------+---------------+------------+
| id | i | b | f | m | mb | t | s | j |
+---------------------+------+---------------+----------+------+-----------------------------+-----------+---------------+------------+
| 5045949922868723723 | 123 | 1099511627776 | 1.200000 | 1,2 | 1099511627776,1099511627777 | text here | test@mail.com | {"a": 123} |
+---------------------+------+---------------+----------+------+-----------------------------+-----------+---------------+------------+
1 row in set (0.00 sec){"table":"t","_id":2,"created":true,"result":"created","status":201}Manticore предоставляет функциональность генерации автоматического ID для столбца ID документов, вставляемых или заменяемых в таблицу реального времени или Percolate таблицу. Генератор создаёт уникальный ID для документа с определёнными гарантиями, но его не следует считать автоинкрементным ID.
Сгенерированное значение ID гарантированно уникально при следующих условиях:
- Значение server_id текущего сервера находится в диапазоне от 0 до 127 и является уникальным среди узлов в кластере, или используется значение по умолчанию, сгенерированное из MAC-адреса в качестве сида
- Системное время не меняется для узла Manticore между перезапусками сервера
- Автоматический ID генерируется менее 16 миллионов раз в секунду между перезапусками поискового сервера
Генератор автоматических ID создает 64-битное целое число для идентификатора документа и использует следующую схему:
- Биты с 0 по 23 образуют счетчик, который увеличивается при каждом вызове генератора автоматических ID
- Биты с 24 по 55 представляют Unix-время запуска сервера
- Биты с 56 по 63 соответствуют server_id
Эта схема гарантирует, что сгенерированный ID уникален среди всех узлов в кластере и что данные, вставленные в разные узлы кластера, не создают коллизий между узлами.
В результате, первый ID от генератора, используемый для автоматического ID, НЕ равен 1, а является большим числом. Кроме того, поток документов, вставленных в таблицу, может иметь не последовательные значения ID, если между вызовами происходят вставки в другие таблицы, поскольку генератор ID является единым на сервере и используется всеми его таблицами.
- SQL
- JSON
- PHP
- Python
- Python-asyncio
- Javascript
- Java
- C#
- Rust
INSERT INTO products(title,price) VALUES ('Crossbody Bag with Tassel', 19.85);
INSERT INTO products VALUES (0,'Yello bag', 4.95);
select * from products;POST /insert
{
"table":"products",
"id":0,
"doc":
{
"title" : "Yellow bag"
}
}
GET /search
{
"table":"products",
"query":{
"query_string":""
}
}$index->addDocuments([
['id' => 0, 'title' => 'Yellow bag']
]);indexApi.insert({"table" : "products", "id" : 0, "doc" : {"title" : "Yellow bag"}})await indexApi.insert({"table" : "products", "id" : 0, "doc" : {"title" : "Yellow bag"}})res = await indexApi.insert({"table" : "products", "id" : 0, "doc" : {"title" : "Yellow bag"}});newdoc = new InsertDocumentRequest();
HashMap<String,Object> doc = new HashMap<String,Object>(){{
put("title","Yellow bag");
}};
newdoc.index("products").id(0L).setDoc(doc);
sqlresult = indexApi.insert(newdoc);Dictionary<string, Object> doc = new Dictionary<string, Object>();
doc.Add("title", "Yellow bag");
InsertDocumentRequest newdoc = new InsertDocumentRequest(index: "products", id: 0, doc: doc);
var sqlresult = indexApi.Insert(newdoc);let doc = HashMap::new();
doc.insert("title".to_string(), serde_json::json!("Yellow bag"));
let insert_req = InsertDocumentRequest {
table: serde_json::json!("products"),
doc: serde_json::json!(doc),
id: serde_json::json!(0),
..Default::default(),
};
let insert_res = index_api.insert(insert_req).await;+---------------------+-----------+---------------------------+
| id | price | title |
+---------------------+-----------+---------------------------+
| 1657860156022587404 | 19.850000 | Crossbody Bag with Tassel |
| 1657860156022587405 | 4.950000 | Yello bag |
+---------------------+-----------+---------------------------+{
"took": 0,
"timed_out": false,
"hits": {
"total": 1,
"hits": [
{
"_id": 1657860156022587406,
"_score": 1,
"_source": {
"price": 0,
"title": "Yellow bag"
}
}
]
}
}CALL UUID_SHORT(N)
Оператор CALL UUID_SHORT(N) позволяет сгенерировать N уникальных 64-битных ID за один вызов без вставки каких-либо документов. Это особенно полезно, когда вам нужно предварительно сгенерировать ID в Manticore для использования в других системах или решениях хранения данных. Например, вы можете сгенерировать автоматические ID в Manticore, а затем использовать их в другой базе данных, приложении или рабочем процессе, обеспечивая согласованные и уникальные идентификаторы в разных средах.
- Example
CALL UUID_SHORT(3)+---------------------+
| uuid_short() |
+---------------------+
| 1227930988733973183 |
| 1227930988733973184 |
| 1227930988733973185 |
+---------------------+Вы можете вставлять в таблицу реального времени не только один документ, но и сколько угодно. Совершенно нормально вставлять пакеты из десятков тысяч документов в таблицу реального времени. Однако важно учитывать следующие моменты:
- Чем больше пакет, тем выше задержка каждой операции вставки
- Чем больше пакет, тем выше скорость индексации, которую вы можете ожидать
- Возможно, вы захотите увеличить значение max_packet_size, чтобы разрешить более крупные пакеты
- Обычно каждая операция массовой вставки считается одной транзакцией с гарантией атомарности, поэтому вы либо получите все новые документы в таблице сразу, либо, в случае сбоя, ни один из них не будет добавлен. Подробнее о пустой строке или переключении на другую таблицу см. в примере "JSON".
Обратите внимание, что HTTP-эндпоинт /bulk не поддерживает автоматическое создание таблиц (автосхему). Только HTTP-эндпоинт /_bulk (Elasticsearch-подобный) и SQL-интерфейс поддерживают эту функцию. HTTP-эндпоинт /_bulk (Elasticsearch-подобный) позволяет включать имя кластера в имя таблицы в формате cluster_name:table_name.
Эндпоинт /_bulk принимает идентификаторы документов в том же формате, что и Elasticsearch, и вы также можете включить id в сам документ:
{ "index": { "table" : "products", "_id" : "1" } }
{ "title" : "Crossbody Bag with Tassel", "price": 19.85 }
или
{ "index": { "table" : "products" } }
{ "title" : "Crossbody Bag with Tassel", "price": 19.85, "id": "1" }
Эндпоинт /bulk (режим Manticore) поддерживает поблочное кодирование передачи. Вы можете использовать его для передачи больших пакетов. Это:
- снижает пиковое использование оперативной памяти, уменьшая риск OOM
- уменьшает время отклика
- позволяет обойти ограничение max_packet_size и передавать пакеты гораздо больше максимально разрешенного значения
max_packet_size(128 МБ), например, по 1 ГБ за раз.
- SQL
- JSON
- Elasticsearch
- PHP
- Python
- Python-asyncio
- Javascript
- Java
- C#
- Rust
Для массовой вставки просто укажите больше документов в скобках после VALUES(). Синтаксис:
INSERT INTO <table name>[(column1, column2, ...)] VALUES(value1[, value2 , ...]), (...)Необязательный список имен столбцов позволяет явно указать значения для некоторых столбцов, присутствующих в таблице. Все остальные столбцы будут заполнены значениями по умолчанию (0 для скалярных типов, пустая строка для строковых типов).
Например:
INSERT INTO products(title,price) VALUES ('Crossbody Bag with Tassel', 19.85), ('microfiber sheet set', 19.99), ('Pet Hair Remover Glove', 7.99);Синтаксис в целом такой же, как и для вставки одного документа. Просто предоставьте больше строк, по одной для каждого документа, и используйте эндпоинт /bulk вместо /insert. Заключите каждый документ в узел "insert". Обратите внимание, что это также требует:
Content-Type: application/x-ndjson- Данные должны быть отформатированы как JSON с разделителями-переводами строк (NDJSON). По сути, это означает, что каждая строка должна содержать ровно один JSON-оператор и заканчиваться символом новой строки
\nи, возможно,\r.
Эндпоинт /bulk поддерживает запросы 'insert', 'replace', 'delete' и 'update'. Имейте в виду, что вы можете направлять операции в несколько таблиц, но транзакции возможны только для одной таблицы. Если вы укажете больше, Manticore соберет операции, направленные в одну таблицу, в одну транзакцию. При смене таблицы он зафиксирует собранные операции и начнет новую транзакцию для новой таблицы. Пустая строка, разделяющая пакеты, также приводит к фиксации предыдущего пакета и началу новой транзакции.
В ответе на запрос /bulk вы можете найти следующие поля:
- "errors": показывает, произошли ли какие-либо ошибки (true/false)
- "error": описывает произошедшую ошибку
- "current_line": номер строки, на которой выполнение остановилось (или завершилось сбоем); пустые строки, включая первую пустую строку, также учитываются
- "skipped_lines": количество незафиксированных строк, начиная с
current_lineи двигаясь назад
POST /bulk
-H "Content-Type: application/x-ndjson" -d '
{"insert": {"table":"products", "id":1, "doc": {"title":"Crossbody Bag with Tassel","price" : 19.85}}}
{"insert":{"table":"products", "id":2, "doc": {"title":"microfiber sheet set","price" : 19.99}}}
'
POST /bulk
-H "Content-Type: application/x-ndjson" -d '
{"insert":{"table":"test1","id":21,"doc":{"int_col":1,"price":1.1,"title":"bulk doc one"}}}
{"insert":{"table":"test1","id":22,"doc":{"int_col":2,"price":2.2,"title":"bulk doc two"}}}
{"insert":{"table":"test1","id":23,"doc":{"int_col":3,"price":3.3,"title":"bulk doc three"}}}
{"insert":{"table":"test2","id":24,"doc":{"int_col":4,"price":4.4,"title":"bulk doc four"}}}
{"insert":{"table":"test2","id":25,"doc":{"int_col":5,"price":5.5,"title":"bulk doc five"}}}
'ПРИМЕЧАНИЕ:
_bulkтребует Manticore Buddy, если таблица еще не существует. Если это не работает, убедитесь, что Buddy установлен.
POST /_bulk
-H "Content-Type: application/x-ndjson" -d '
{ "index" : { "table" : "products" } }
{ "title" : "Yellow Bag", "price": 12 }
{ "create" : { "table" : "products" } }
{ "title" : "Red Bag", "price": 12.5, "id": 3 }
'Используйте метод addDocuments():
$index->addDocuments([
['id' => 1, 'title' => 'Crossbody Bag with Tassel', 'price' => 19.85],
['id' => 2, 'title' => 'microfiber sheet set', 'price' => 19.99],
['id' => 3, 'title' => 'Pet Hair Remover Glove', 'price' => 7.99]
]);docs = [ \
{"insert": {"table" : "products", "id" : 1, "doc" : {"title" : "Crossbody Bag with Tassel", "price" : 19.85}}}, \
{"insert": {"table" : "products", "id" : 2, "doc" : {"title" : "microfiber sheet set", "price" : 19.99}}}, \
{"insert": {"table" : "products", "id" : 3, "doc" : {"title" : "CPet Hair Remover Glove", "price" : 7.99}}}
]
res = indexApi.bulk('\n'.join(map(json.dumps,docs)))docs = [ \
{"insert": {"table" : "products", "id" : 1, "doc" : {"title" : "Crossbody Bag with Tassel", "price" : 19.85}}}, \
{"insert": {"table" : "products", "id" : 2, "doc" : {"title" : "microfiber sheet set", "price" : 19.99}}}, \
{"insert": {"table" : "products", "id" : 3, "doc" : {"title" : "CPet Hair Remover Glove", "price" : 7.99}}}
]
res = await indexApi.bulk('\n'.join(map(json.dumps,docs)))let docs = [
{"insert": {"table" : "products", "id" : 3, "doc" : {"title" : "Crossbody Bag with Tassel", "price" : 19.85}}},
{"insert": {"table" : "products", "id" : 4, "doc" : {"title" : "microfiber sheet set", "price" : 19.99}}},
{"insert": {"table" : "products", "id" : 5, "doc" : {"title" : "CPet Hair Remover Glove", "price" : 7.99}}}
];
res = await indexApi.bulk(docs.map(e=>JSON.stringify(e)).join('\n'));String body = "{\"insert\": {\"index\" : \"products\", \"id\" : 1, \"doc\" : {\"title\" : \"Crossbody Bag with Tassel\", \"price\" : 19.85}}}"+"\n"+
"{\"insert\": {\"index\" : \"products\", \"id\" : 4, \"doc\" : {\"title\" : \"microfiber sheet set\", \"price\" : 19.99}}}"+"\n"+
"{\"insert\": {\"index\" : \"products\", \"id\" : 5, \"doc\" : {\"title\" : \"CPet Hair Remover Glove\", \"price\" : 7.99}}}"+"\n";
BulkResponse bulkresult = indexApi.bulk(body);string body = "{\"insert\": {\"index\" : \"products\", \"id\" : 1, \"doc\" : {\"title\" : \"Crossbody Bag with Tassel\", \"price\" : 19.85}}}"+"\n"+
"{\"insert\": {\"index\" : \"products\", \"id\" : 4, \"doc\" : {\"title\" : \"microfiber sheet set\", \"price\" : 19.99}}}"+"\n"+
"{\"insert\": {\"index\" : \"products\", \"id\" : 5, \"doc\" : {\"title\" : \"CPet Hair Remover Glove\", \"price\" : 7.99}}}"+"\n";
BulkResponse bulkresult = indexApi.Bulk(string.Join("\n", docs));let bulk_body = r#"{"insert": "index" : "products", "id" : 1, "doc" : {"title" : "Crossbody Bag with Tassel", "price" : 19.85}}}
{"insert": {"index" : "products", "id" : 4, "doc" : {"title" : "microfiber sheet set", "price" : 19.99}}}
{"insert": {"index" : "products", "id" : 5, "doc" : {"title" : "CPet Hair Remover Glove", "price" : 7.99}}}
"#;
index_api.bulk(bulk_body).await;Query OK, 3 rows affected (0.01 sec)Выражения в настоящее время не поддерживаются в INSERT, и значения должны быть указаны явно.
{
"items": [
{
"bulk": {
"table": "products",
"_id": 2,
"created": 2,
"deleted": 0,
"updated": 0,
"result": "created",
"status": 201
}
}
],
"current_line": 4,
"skipped_lines": 0,
"errors": false,
"error": ""
}
{
"items": [
{
"bulk": {
"table": "test1",
"_id": 22,
"created": 2,
"deleted": 0,
"updated": 0,
"result": "created",
"status": 201
}
},
{
"bulk": {
"table": "test1",
"_id": 23,
"created": 1,
"deleted": 0,
"updated": 0,
"result": "created",
"status": 201
}
},
{
"bulk": {
"table": "test2",
"_id": 25,
"created": 2,
"deleted": 0,
"updated": 0,
"result": "created",
"status": 201
}
}
],
"current_line": 8,
"skipped_lines": 0,
"errors": false,
"error": ""
}{
"items": [
{
"table": {
"table": "products",
"_type": "doc",
"_id": 1657860156022587406,
"_version": 1,
"result": "created",
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1,
"status": 201
}
},
{
"create": {
"table": "products",
"_type": "doc",
"_id": 3,
"_version": 1,
"result": "created",
"_shards": {
"total": 1,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1,
"status": 201
}
}
],
"errors": false,
"took": 1
}- SQL
- JSON
- Elasticsearch
- PHP
- Python
- Python-asyncio
- Javascript
- Java
- C#
- Rust
INSERT INTO products(title, sizes) VALUES('shoes', (40,41,42,43));POST /insert
{
"table":"products",
"id":1,
"doc":
{
"title" : "shoes",
"sizes" : [40, 41, 42, 43]
}
}POST /products/_create/1
{
"title": "shoes",
"sizes" : [40, 41, 42, 43]
}Или, альтернативно
POST /products/_doc/
{
"title": "shoes",
"sizes" : [40, 41, 42, 43]
}$index->addDocument(
['title' => 'shoes', 'sizes' => [40,41,42,43]],
1
);indexApi.insert({"table" : "products", "id" : 0, "doc" : {"title" : "Yellow bag","sizes":[40,41,42,43]}})await indexApi.insert({"table" : "products", "id" : 0, "doc" : {"title" : "Yellow bag","sizes":[40,41,42,43]}})res = await indexApi.insert({"table" : "products", "id" : 0, "doc" : {"title" : "Yellow bag","sizes":[40,41,42,43]}});newdoc = new InsertDocumentRequest();
HashMap<String,Object> doc = new HashMap<String,Object>(){{
put("title","Yellow bag");
put("sizes",new int[]{40,41,42,43});
}};
newdoc.index("products").id(0L).setDoc(doc);
sqlresult = indexApi.insert(newdoc);Dictionary<string, Object> doc = new Dictionary<string, Object>();
doc.Add("title", "Yellow bag");
doc.Add("sizes", new List<Object> {40,41,42,43});
InsertDocumentRequest newdoc = new InsertDocumentRequest(index: "products", id: 0, doc: doc);
var sqlresult = indexApi.Insert(newdoc);let mut doc = HashMap::new();
doc.insert("title".to_string(), serde_json::json!("Yellow bag"));
doc.insert("sizes".to_string(), serde_json::json!([40,41,42,43]));
let insert_req = InsertDocumentRequest::new("products".to_string(), serde_json::json!(doc));
let insert_res = index_api.insert(insert_req).await;Значение JSON может быть вставлено как экранированная строка (через SQL или JSON) или как объект JSON (через JSON-интерфейс).
- SQL
- JSON
- Elasticsearch
- PHP
- Python
- Python-asyncio
- Javascript
- Java
- C#
- Rust
INSERT INTO products VALUES (1, 'shoes', '{"size": 41, "color": "red"}');Значение JSON может быть вставлено как объект JSON
POST /insert
{
"table":"products",
"id":1,
"doc":
{
"title" : "shoes",
"meta" : {
"size": 41,
"color": "red"
}
}
}Значение JSON также может быть вставлено как строка, содержащая экранированный JSON:
POST /insert
{
"table":"products",
"id":1,
"doc":
{
"title" : "shoes",
"meta" : "{\"size\": 41, \"color\": \"red\"}"
}
}POST /products/_create/1
{
"title": "shoes",
"meta" : {
"size": 41,
"color": "red"
}
}Или, альтернативно
POST /products/_doc/
{
"title": "shoes",
"meta" : {
"size": 41,
"color": "red"
}
}$index->addDocument(
['title' => 'shoes', 'meta' => '{"size": 41, "color": "red"}'],
1
);indexApi = api = manticoresearch.IndexApi(client)
indexApi.insert({"table" : "products", "id" : 0, "doc" : {"title" : "Yellow bag","meta":'{"size": 41, "color": "red"}'}})indexApi = api = manticoresearch.IndexApi(client)
await indexApi.insert({"table" : "products", "id" : 0, "doc" : {"title" : "Yellow bag","meta":'{"size": 41, "color": "red"}'}})res = await indexApi.insert({"table" : "products", "id" : 0, "doc" : {"title" : "Yellow bag","meta":'{"size": 41, "color": "red"}'}});newdoc = new InsertDocumentRequest();
HashMap<String,Object> doc = new HashMap<String,Object>(){{
put("title","Yellow bag");
put("meta",
new HashMap<String,Object>(){{
put("size",41);
put("color","red");
}});
}};
newdoc.index("products").id(0L).setDoc(doc);
sqlresult = indexApi.insert(newdoc);Dictionary<string, Object> meta = new Dictionary<string, Object>();
meta.Add("size", 41);
meta.Add("color", "red");
Dictionary<string, Object> doc = new Dictionary<string, Object>();
doc.Add("title", "Yellow bag");
doc.Add("meta", meta);
InsertDocumentRequest newdoc = new InsertDocumentRequest(index: "products", id: 0, doc: doc);
var sqlresult = indexApi.Insert(newdoc);let mut meta = HashMap::new();
metadoc.insert("size".to_string(), serde_json::json!(41));
meta.insert("color".to_string(), serde_json::json!("red"));
let mut doc = HashMap::new();
doc.insert("title".to_string(), serde_json::json!("Yellow bag"));
doc.insert("meta".to_string(), serde_json::json!(meta));
let insert_req = InsertDocumentRequest::new("products".to_string(), serde_json::json!(doc));
let insert_res = index_api.insert(insert_req).await;В percolate таблице хранятся документы, которые являются правилами percolate запросов, и они должны строго соответствовать схеме из четырёх полей:
| поле | тип | описание |
|---|---|---|
| id | bigint | Идентификатор правила PQ (если опущен, будет назначен автоматически) |
| query | string | Полнотекстовый запрос (может быть пустым), совместимый с percolate таблицей |
| filters | string | Дополнительные фильтры по не-полнотекстовым полям (может быть пустым), совместимые с percolate таблицей |
| tags | string | Строка с одним или несколькими тегами, разделёнными запятыми, которые могут использоваться для выборочного отображения/удаления сохранённых запросов |
Любые другие имена полей не поддерживаются и вызовут ошибку.
Внимание: Вставка/замена правил PQ в формате JSON через SQL не будет работать. Другими словами, специфичные для JSON операторы (match и т.д.) будут рассматриваться просто как часть текста правила, который должен совпадать с документами. Если вы предпочитаете синтаксис JSON, используйте HTTP endpoint вместо INSERT/REPLACE.
- SQL
- JSON
- PHP
- Python
- Python-asyncio
- Javascript
- Java
- C#
- Rust
INSERT INTO pq(id, query, filters) VALUES (1, '@title shoes', 'price > 5');
INSERT INTO pq(id, query, tags) VALUES (2, '@title bag', 'Louis Vuitton');
SELECT * FROM pq;Существует два способа добавления percolate запроса в percolate таблицу:
-
Запрос в формате JSON /search, совместимый с json/search
PUT /pq/pq_table/doc/1 { "query": { "match": { "title": "shoes" }, "range": { "price": { "gt": 5 } } }, "tags": ["Loius Vuitton"] } -
Запрос в формате SQL, описанный в search query syntax
PUT /pq/pq_table/doc/2 { "query": { "ql": "@title shoes" }, "filters": "price > 5", "tags": ["Loius Vuitton"] }
$newstoredquery = [
'table' => 'test_pq',
'body' => [
'query' => [
'match' => [
'title' => 'shoes'
]
],
'range' => [
'price' => [
'gt' => 5
]
]
],
'tags' => ['Loius Vuitton']
];
$client->pq()->doc($newstoredquery);newstoredquery ={"table" : "test_pq", "id" : 2, "doc" : {"query": {"ql": "@title shoes"},"filters": "price > 5","tags": ["Loius Vuitton"]}}
indexApi.insert(newstoredquery)newstoredquery ={"table" : "test_pq", "id" : 2, "doc" : {"query": {"ql": "@title shoes"},"filters": "price > 5","tags": ["Loius Vuitton"]}}
await indexApi.insert(newstoredquery)newstoredquery ={"table" : "test_pq", "id" : 2, "doc" : {"query": {"ql": "@title shoes"},"filters": "price > 5","tags": ["Loius Vuitton"]}};
indexApi.insert(newstoredquery);newstoredquery = new HashMap<String,Object>(){{
put("query",new HashMap<String,Object >(){{
put("q1","@title shoes");
put("filters","price>5");
put("tags",new String[] {"Loius Vuitton"});
}});
}};
newdoc.index("test_pq").id(2L).setDoc(doc);
indexApi.insert(newdoc);Dictionary<string, Object> query = new Dictionary<string, Object>();
query.Add("q1", "@title shoes");
query.Add("filters", "price>5");
query.Add("tags", new List<string> {"Loius Vuitton"});
Dictionary<string, Object> newstoredquery = new Dictionary<string, Object>();
newstoredquery.Add("query", query);
InsertDocumentRequest newdoc = new InsertDocumentRequest(index: "test_pq", id: 2, doc: doc);
indexApi.Insert(newdoc);let mut pq_doc = HashMap::new();
pq_doc.insert("q1".to_string(), serde_json::json!("@title shoes"));
pq_doc.insert("filters".to_string(), serde_json::json!("price>5"));
pq_doc.insert("tags".to_string(), serde_json::json!(["Louis Vitton"]));
let mut doc = HashMap::new();
pq_doc.insert("query".to_string(), serde_json::json!(pq_doc));
let insert_req = InsertDocumentRequest::new("test_pq".to_string(), serde_json::json!(doc));
let insert_res = index_api.insert(insert_req).await;+------+--------------+---------------+---------+
| id | query | tags | filters |
+------+--------------+---------------+---------+
| 1 | @title shoes | | price>5 |
| 2 | @title bag | Louis Vuitton | |
+------+--------------+---------------+---------+Если вы не укажете ID, он будет назначен автоматически. Подробнее об авто-ID можно прочитать здесь.
- SQL
- JSON
- PHP
- Python
- Python-asyncio
- Javascript
- Java
- C#
- Rust
INSERT INTO pq(query, filters) VALUES ('wristband', 'price > 5');
SELECT * FROM pq;PUT /pq/pq_table/doc
{
"query": {
"match": {
"title": "shoes"
},
"range": {
"price": {
"gt": 5
}
}
},
"tags": ["Loius Vuitton"]
}
PUT /pq/pq_table/doc
{
"query": {
"ql": "@title shoes"
},
"filters": "price > 5",
"tags": ["Loius Vuitton"]
}$newstoredquery = [
'table' => 'pq_table',
'body' => [
'query' => [
'match' => [
'title' => 'shoes'
]
],
'range' => [
'price' => [
'gt' => 5
]
]
],
'tags' => ['Loius Vuitton']
];
$client->pq()->doc($newstoredquery);indexApi = api = manticoresearch.IndexApi(client)
newstoredquery ={"table" : "test_pq", "doc" : {"query": {"ql": "@title shoes"},"filters": "price > 5","tags": ["Loius Vuitton"]}}
indexApi.insert(store_query)indexApi = api = manticoresearch.IndexApi(client)
newstoredquery ={"table" : "test_pq", "doc" : {"query": {"ql": "@title shoes"},"filters": "price > 5","tags": ["Loius Vuitton"]}}
await indexApi.insert(store_query)newstoredquery ={"table" : "test_pq", "doc" : {"query": {"ql": "@title shoes"},"filters": "price > 5","tags": ["Loius Vuitton"]}};
res = await indexApi.insert(store_query);newstoredquery = new HashMap<String,Object>(){{
put("query",new HashMap<String,Object >(){{
put("q1","@title shoes");
put("filters","price>5");
put("tags",new String[] {"Loius Vuitton"});
}});
}};
newdoc.index("test_pq").setDoc(doc);
indexApi.insert(newdoc);Dictionary<string, Object> query = new Dictionary<string, Object>();
query.Add("q1", "@title shoes");
query.Add("filters", "price>5");
query.Add("tags", new List<string> {"Loius Vuitton"});
Dictionary<string, Object> newstoredquery = new Dictionary<string, Object>();
newstoredquery.Add("query", query);
InsertDocumentRequest newdoc = new InsertDocumentRequest(index: "test_pq", doc: doc);
indexApi.Insert(newdoc);let mut pq_doc = HashMap::new();
pq_doc.insert("q1".to_string(), serde_json::json!("@title shoes"));
pq_doc.insert("filters".to_string(), serde_json::json!("price>5"));
pq_doc.insert("tags".to_string(), serde_json::json!(["Louis Vitton"]));
let mut doc = HashMap::new();
pq_doc.insert("query".to_string(), serde_json::json!(pq_doc));
let insert_req = InsertDocumentRequest::new("test_pq".to_string(), serde_json::json!(doc));
let insert_res = index_api.insert(insert_req).await;+---------------------+-----------+------+---------+
| id | query | tags | filters |
+---------------------+-----------+------+---------+
| 1657843905795719192 | wristband | | price>5 |
+---------------------+-----------+------+---------+{
"table": "pq_table",
"type": "doc",
"_id": 1657843905795719196,
"result": "created"
}
{
"table": "pq_table",
"type": "doc",
"_id": 1657843905795719198,
"result": "created"
}Array(
[index] => pq_table
[type] => doc
[_id] => 1657843905795719198
[result] => created
){'created': True,
'found': None,
'id': 1657843905795719198,
'table': 'test_pq',
'result': 'created'}{'created': True,
'found': None,
'id': 1657843905795719198,
'table': 'test_pq',
'result': 'created'}{"table":"test_pq","_id":1657843905795719198,"created":true,"result":"created"}В случае опущенной схемы в SQL команде INSERT ожидаются следующие параметры:
- ID. Вы можете использовать
0в качестве ID для запуска автоматической генерации ID. - Query - Полнотекстовый запрос.
- Tags - Строка тегов правила PQ.
- Filters - Дополнительные фильтры по атрибутам.
- SQL
INSERT INTO pq VALUES (0, '@title shoes', '', '');
INSERT INTO pq VALUES (0, '@title shoes', 'Louis Vuitton', '');
SELECT * FROM pq;+---------------------+--------------+---------------+---------+
| id | query | tags | filters |
+---------------------+--------------+---------------+---------+
| 2810855531667783688 | @title shoes | | |
| 2810855531667783689 | @title shoes | Louis Vuitton | |
+---------------------+--------------+---------------+---------+Чтобы заменить существующее правило PQ на новое в SQL, просто используйте обычную команду REPLACE. Существует специальный синтаксис ?refresh=1 для замены правила PQ, определённого в режиме JSON, через HTTP JSON интерфейс.
- SQL
- JSON
mysql> select * from pq;
+---------------------+--------------+------+---------+
| id | query | tags | filters |
+---------------------+--------------+------+---------+
| 2810823411335430148 | @title shoes | | |
+---------------------+--------------+------+---------+
1 row in set (0.00 sec)
mysql> replace into pq(id,query) values(2810823411335430148,'@title boots');
Query OK, 1 row affected (0.00 sec)
mysql> select * from pq;
+---------------------+--------------+------+---------+
| id | query | tags | filters |
+---------------------+--------------+------+---------+
| 2810823411335430148 | @title boots | | |
+---------------------+--------------+------+---------+
1 row in set (0.00 sec)GET /pq/pq/doc/2810823411335430149
{
"took": 0,
"timed_out": false,
"hits": {
"total": 1,
"hits": [
{
"_id": 2810823411335430149,
"_score": 1,
"_source": {
"query": {
"match": {
"title": "shoes"
}
},
"tags": "",
"filters": ""
}
}
]
}
}
PUT /pq/pq/doc/2810823411335430149?refresh=1 -d '{
"query": {
"match": {
"title": "boots"
}
}
}'
GET /pq/pq/doc/2810823411335430149
{
"took": 0,
"timed_out": false,
"hits": {
"total": 1,
"hits": [
{
"_id": 2810823411335430149,
"_score": 1,
"_source": {
"query": {
"match": {
"title": "boots"
}
},
"tags": "",
"filters": ""
}
}
]
}
}Вы можете загружать данные в Manticore из внешних хранилищ с помощью различных методов:
- Индексатор для получения данных из различных баз данных в обычные таблицы.
- Интеграции с Logstash, Filebeat и Vector.dev, чтобы помещать данные в таблицы реального времени Manticore из этих инструментов.
- Интеграция с Kafka для синхронизации данных из тем Kafka в таблицу реального времени.
Простые таблицы — это таблицы, которые создаются однократно путём получения данных при создании из одного или нескольких источников. Простая таблица является неизменяемой, так как документы не могут быть добавлены или удалены в течение её времени жизни. Можно только обновлять значения числовых атрибутов (включая MVA). Обновление данных возможно только путём воссоздания всей таблицы.
Простые таблицы доступны только в Plain режиме, а их определение состоит из объявления таблицы и одного или нескольких объявлений источников. Сбор данных и создание таблицы выполняется не сервером searchd, а вспомогательным инструментом indexer.
Indexer — это инструмент командной строки, который можно запускать напрямую из командной строки или из shell-скриптов.
При вызове он может принимать ряд аргументов, но также есть несколько собственных настроек в конфигурационном файле Manticore.
В типичном сценарии indexer выполняет следующие действия:
- Извлекает данные из источника
- Строит простую таблицу
- Записывает файлы таблицы
- (Опционально) Информирует поисковый сервер о новой таблице, что вызывает ротацию таблиц
Инструмент indexer используется для создания простых таблиц в Manticore Search. Его общий синтаксис:
indexer [OPTIONS] [table_name1 [table_name2 [...]]]
При создании таблиц с indexer сгенерированные файлы таблиц должны иметь права, позволяющие searchd читать, записывать и удалять их. В официальных пакетах для Linux searchd запускается от имени пользователя manticore. Поэтому indexer также должен выполняться от имени пользователя manticore:
sudo -u manticore indexer ...
Если вы запускаете searchd иначе, возможно, потребуется опустить sudo -u manticore. Просто убедитесь, что пользователь, под которым работает ваш экземпляр searchd, имеет права на чтение/запись к таблицам, созданным с помощью indexer.
Для создания простой таблицы нужно перечислить таблицу (или таблицы), которые вы хотите обработать. Например, если в вашем файле manticore.conf указаны две таблицы, mybigindex и mysmallindex, можно выполнить:
sudo -u manticore indexer mysmallindex mybigindex
Также можно использовать подстановочные токены для сопоставления имён таблиц:
?соответствует одному любому символу*соответствует любому количеству любых символов%соответствует отсутствию или одному любому символу
sudo -u manticore indexer indexpart*main --rotate
Коды выхода indexer следующие:
- 0: всё прошло успешно
- 1: возникла проблема при индексации (и если указан
--rotate, он был пропущен) или операция выдала предупреждение - 2: индексация прошла успешно, но попытка
--rotateне удалась
Вы также можете запускать indexer с помощью следующего unit-файла systemctl:
systemctl start --no-block manticore-indexer
Или, если хотите собрать конкретную таблицу:
systemctl start --no-block manticore-indexer@specific-table-name
Используйте команду systemctl set-environment INDEXER_CONFIG, чтобы запускать Indexer с пользовательской конфигурацией, заменяющей настройки по умолчанию.
Команда systemctl set-environment INDEXER_ARGS позволяет добавить собственные опции запуска для Indexer. Полный список опций командной строки смотрите здесь.
Например, чтобы запустить Indexer в тихом режиме, выполните:
systemctl set-environment INDEXER_ARGS='--quiet'
systemctl restart manticore-indexer
Чтобы отменить изменения, выполните:
systemctl set-environment INDEXER_ARGS=''
systemctl restart manticore-indexer
-
--config <file>(-c <file>как сокращение) указываетindexerиспользовать указанный файл в качестве конфигурации. Обычно он ищетmanticore.confв каталоге установки (например,/etc/manticoresearch/manticore.conf), затем в текущем каталоге, в котором вызываетсяindexerиз shell. Это особенно полезно в общих средах, где бинарные файлы установлены в глобальную папку, например/usr/bin/, но вы хотите предоставить пользователям возможность создавать свои собственные настройки Manticore, либо если хотите запустить несколько экземпляров на одном сервере. В таких случаях вы можете разрешить им создавать собственные файлыmanticore.confи передавать ихindexerс помощью этой опции. Например:sudo -u manticore indexer --config /home/myuser/manticore.conf mytable -
--allуказываетindexerобновлять все таблицы, перечисленные вmanticore.conf, вместо перечисления отдельных таблиц. Это полезно в небольших конфигурациях или для cron-задач или задач обслуживания, где весь набор таблиц пересоздаётся каждый день, неделю или любой другой удобный период. Обратите внимание, что так как--allпытается обновить все найденные таблицы в конфигурации, он выдаст предупреждение, если встретит RealTime таблицы, и код выхода команды будет1, а не0, даже если простые таблицы завершились успешно. Пример использования:sudo -u manticore indexer --config /home/myuser/manticore.conf --all -
--rotateиспользуется для ротации таблиц. Если у вас нет ситуации, в которой можно отключить функцию поиска без неудобств для пользователей, вам почти наверняка нужно держать поиск запущенным во время индексации новых документов.--rotateсоздаёт вторую таблицу, параллельную первой (в том же месте, просто с включением.newв имена файлов). После завершенияindexerуведомляетsearchdс помощью сигналаSIGHUP, иsearchdпопробует переименовать таблицы (переименовать существующие, добавляя.old, и переименовать.newв оригинальные имена), затем начнёт обслуживать из новых файлов. В зависимости от настройки seamless_rotate может быть небольшая задержка перед возможностью искать в новых таблицах. Если одновременно ротируются несколько таблиц, связанных отношениями killlist_target, ротация начнётся с таблиц, не являющихся целями, и закончится таблицами в конце цепочки целей. Пример использования:sudo -u manticore indexer --rotate --all -
--quietуказываетindexerне выводить ничего, если нет ошибок. Обычно используется для cron-задач или других скриптов, где вывод не нужен, кроме случаев ошибок. Пример использования:sudo -u manticore indexer --rotate --all --quiet -
--noprogressне отображает детали прогресса по мере выполнения. Вместо этого окончательные сведения о статусе (например, количество проиндексированных документов, скорость индексирования и так далее) выводятся только после завершения индексирования. В случаях, когда скрипт не запускается в консоли (или 'tty'), этот режим включён по умолчанию. Пример использования:sudo -u manticore indexer --rotate --all --noprogress -
--buildstops <outputfile.text> <N>просматривает исходную таблицу так, как если бы она индексировала данные, и создаёт список терминов, которые индексируются. Другими словами, он формирует список всех поисковых терминов, которые становятся частью таблицы. Обратите внимание, что таблица не обновляется, данные просто обрабатываются так, как будто происходит индексирование, включая выполнение запросов, определённых с помощью sql_query_pre или sql_query_post. Вoutputfile.txtбудет содержаться список слов, по одному в строке, отсортированный по частоте, начиная с самых частых, аNзадаёт максимальное количество слов в списке. Если это число достаточно велико, чтобы охватить все слова в таблице, будет возвращено именно столько слов. Такой словарь может использоваться в клиентских приложениях для функций вроде "Вы имели в виду…", обычно в сочетании с--buildfreqs, указанным ниже. Пример:sudo -u manticore indexer mytable --buildstops word_freq.txt 1000Это создаст в текущем каталоге документ
word_freq.txtс 1000 наиболее распространённых слов в 'mytable', упорядоченных по убыванию частоты. Обратите внимание, что файл будет относиться к последней проиндексированной таблице при указании нескольких таблиц или--all(то есть последней в списке конфигурационного файла). -
--buildfreqsработает вместе с--buildstops(игнорируется, если--buildstopsне указан). Поскольку--buildstopsпредоставляет список слов, используемых в таблице,--buildfreqsдобавляет количество их вхождений, что полезно для определения, следует ли считать определённые слова стоп-словами, если они слишком часто встречаются. Это также помогает в разработке функций "Вы имели в виду…", где нужно знать, насколько одно слово распространено относительно другого, похожего. Например:sudo -u manticore indexer mytable --buildstops word_freq.txt 1000 --buildfreqsЭто создаст
word_freq.txt, как указано выше, но после каждого слова будет число, показывающее количество его вхождений в рассматриваемой таблице. -
--merge <dst-table> <src-table>используется для физического объединения таблиц, например, в случае схемы main+delta, где основная таблица редко меняется, а дельта-таблица часто пересоздаётся;--mergeприменяется для их объединения. Операция выполняется справа налево — содержимоеsrc-tableанализируется и физически объединяется с содержимымdst-table, результат остаётся вdst-table. В псевдокоде это можно выразить как:dst-table += src-tableПример:sudo -u manticore indexer --merge main delta --rotateВ приведённом примере, где основная таблица — основная, редко изменяемая, а дельта — более часто изменяемая, приведённый вызов
indexerиспользуется для объединения содержимого дельты с основной таблицей и переключения таблиц. -
--merge-dst-range <attr> <min> <max>применяет фильтр диапазона при слиянии. Конкретно, поскольку слияние применяется к целевой таблице (в рамках--merge, игнорируется при отсутствии--merge),indexerбудет фильтровать документы, попадающие в целевую таблицу, и только документы, удовлетворяющие фильтру, окажутся в итоговой таблице. Например, в таблице с атрибутом 'deleted', где 0 означает «не удалён». Такая таблица может быть объединена с:sudo -u manticore indexer --merge main delta --merge-dst-range deleted 0 0Документы, помеченные как удалённые (значение 1), будут исключены из вновь объединённой целевой таблицы. Данный параметр можно указывать несколько раз в командной строке для добавления последовательных фильтров для слияния, каждый из которых должен быть выполнен, чтобы документ стал частью итоговой таблицы.
-
--
merge-killlists(и его короткий псевдоним--merge-klists) изменяет способ обработки списков удалённых при слиянии таблиц. По умолчанию после слияния оба списка удалённых отбрасываются. Это поддерживает наиболее распространённый сценарий слияния main+delta. Однако с включённым этим параметром списки удалённых из обеих таблиц объединяются и сохраняются в целевой таблице. Обратите внимание, что список удалённых из исходной (дельта) таблицы всегда используется для подавления строк из целевой (главной) таблицы. -
--keep-attrsпозволяет повторно использовать существующие атрибуты при переиндексации. При перестроении таблицы идентификатор каждого нового документа проверяется на наличие в "старой" таблице; если найден, его атрибуты переносятся в "новую" таблицу; если нет — используются атрибуты из новой таблицы. Если пользователь обновил атрибуты в таблице, но не обновил источник данных, все изменения будут потеряны при переиндексации; использование--keep-attrsпозволяет сохранить обновлённые значения атрибутов из предыдущей таблицы. Можно указать путь к файлам таблицы, который будет использован вместо пути из конфигурации:sudo -u manticore indexer mytable --keep-attrs=/path/to/index/files -
--keep-attrs-names=<attributes list>позволяет указать атрибуты, которые нужно повторно использовать из существующей таблицы при переиндексации. По умолчанию все атрибуты из существующей таблицы переносятся в новую:sudo -u manticore indexer mytable --keep-attrs=/path/to/table/files --keep-attrs-names=update,state -
--dump-rows <FILE>сохраняет строки, полученные из SQL-источника(ов), в указанный файл в синтаксисе, совместимом с MySQL. Полученные дампы точно представляют данные, как они принимаютсяindexer, и могут помочь воспроизвести ошибки, возникающие во время индексации. Команда выполняет извлечение из источника и создаёт как файлы таблиц, так и файл дампа. -
--print-rt <rt_index> <table>выводит полученные данные из источника в виде INSERT-запросов для таблицы реального времени. Первые строки дампа будут содержать поля и атрибуты таблицы реального времени (как отражение полей и атрибутов обычной таблицы). Команда выполняет извлечение из источника и создаёт как файлы таблиц, так и дамп-вывод. Команду можно использовать какsudo -u manticore indexer -c manticore.conf --print-rt indexrt indexplain > dump.sql. Поддерживаются только источники на базе SQL. Массивы MVA не поддерживаются. -
--sighup-eachполезен, когда вы перестраиваете много больших таблиц и хотите, чтобы каждая была сразу же загружена вsearchd. С--sighup-eachindexerотправляет сигнал SIGHUP в searchd после успешного завершения работы над каждой таблицей. (Поведение по умолчанию — отправить один SIGHUP после построения всех таблиц). -
--nohupполезен, когда вы хотите проверить вашу таблицу с помощью indextool перед фактической загрузкой. Если эта опция включена, indexer не будет отправлять SIGHUP. Файлы таблиц переименовываются в .tmp. Используйте indextool для переименования файлов таблиц в .new и их загрузки. Пример использования:sudo -u manticore indexer --rotate --nohup mytable sudo -u manticore indextool --rotate --check mytable -
--print-queriesвыводит SQL-запросы, которыеindexerотправляет базе данных, вместе с событиями подключения и отключения SQL. Это полезно для диагностики и устранения проблем с SQL-источниками. -
--help(-hдля краткости) выводит список всех параметров, которые можно вызвать вindexer. -
-vотображает версиюindexer.
Вы также можете настроить поведение indexer в конфигурационном файле Manticore в разделе indexer:
indexer {
...
}
lemmatizer_cache = 256M
Размер кэша лемматизатора. Необязательно, по умолчанию 256K.
Наша реализация лемматизатора использует сжатый формат словаря, позволяющий идти на компромисс между использованием памяти и скоростью. Он может выполнять лемматизацию непосредственно сжатых данных, используя больше CPU, но меньше RAM, либо разархивировать и предварительно кэшировать словарь частично или полностью, используя меньше CPU, но больше RAM. Директива lemmatizer_cache позволяет контролировать, сколько точно оперативной памяти может быть выделено под этот несжатый кэш словаря.
В настоящее время доступны только словари ru.pak, en.pak и de.pak. Это русские, английские и немецкие словари. Размер сжатого словаря примерно от 2 до 10 МБ. Обратите внимание, что словарь всё время хранится в памяти. Размер кэша по умолчанию — 256 КБ. Принимаемые размеры кэша — от 0 до 2047 МБ. Безопасно устанавливать размер кэша довольно большим; лемматизатор использует только необходимую память. Например, полный русский словарь разархивируется до примерно 110 МБ; установка lemmatizer_cache выше этого значения не увеличит использование памяти. Даже при разрешённом размере кэша 1024 МБ, если требуется только 110 МБ, будет использовано именно столько.
max_file_field_buffer = 128M
Максимальный адаптивный размер буфера для файловых полей в байтах. Необязательно, по умолчанию 8MB, минимум 1MB.
Буфер файлового поля используется для загрузки файлов, упомянутых в столбцах sql_file_field. Этот буфер адаптивный, начиная с 1 МБ при первом выделении и увеличивается в 2 раза до тех пор, пока либо содержимое файла не загрузится, либо не достигнет максимального размера буфера, указанного в директиве max_file_field_buffer.
Таким образом, если файловые поля не заданы, буфер не выделяется вообще. Если все файлы, загружаемые во время индексации, меньше (например) 2 МБ, но значение max_file_field_buffer равно 128 МБ, пиковое использование буфера всё равно будет только 2 МБ. Однако файлы больше 128 МБ будут полностью пропущены.
max_iops = 40
Максимальное число операций ввода/вывода в секунду для ограничения скорости I/O. Необязательно, по умолчанию 0 (без ограничений).
Опция для ограничения скорости I/O. Ограничивает максимальное количество операций ввода/вывода (чтение или запись) за одну секунду. Значение 0 означает, что ограничений нет.
indexer может создавать всплески интенсивного дискового I/O во время построения таблицы, и может быть желательно ограничить его дискoвую активность (оставив ресурсы для других программ, например searchd). Ограничение скорости I/O помогает в этом. Оно обеспечивает минимальную задержку между последовательными операциями дискового ввода/вывода, выполняемыми indexer. Ограничение I/O может помочь уменьшить деградацию производительности поиска из-за построения. Эта настройка не влияет на другие виды внесения данных, например вставку данных в таблицу реального времени.
max_iosize = 1048576
Максимальный разрешённый размер операции ввода/вывода в байтах для ограничения скорости I/O. Необязательно, по умолчанию 0 (без ограничений).
Опция, связанная с ограничением скорости I/O. Ограничивает максимальный размер файловой операции ввода/вывода (чтения или записи) для всех операций, выполняемых indexer. Значение 0 означает отсутствие ограничений. Операции чтения или записи, превышающие лимит, будут разбиты на несколько меньших операций и посчитаны как несколько операций согласно настройке max_iops. На момент написания все операции ввода/вывода должны быть меньше 256 КБ (размер внутреннего буфера по умолчанию), поэтому значения max_iosize выше 256 КБ не должны иметь эффекта.
max_xmlpipe2_field = 8M
Максимально допустимый размер поля для источника типа XMLpipe2 в байтах. Необязательно, по умолчанию 2 МБ.
mem_limit = 256M
# mem_limit = 262144K # same, but in KB
# mem_limit = 268435456 # same, but in bytes
Ограничение использования оперативной памяти при построении простых таблиц. Необязательный параметр, по умолчанию 128 МБ. Принудительный лимит использования памяти, выше которого indexer не поднимется. Можно указать в байтах, килобайтах (с использованием постфикса K) или мегабайтах (с использованием постфикса M); см. пример. Этот лимит будет автоматически повышен, если установлено чрезвычайно низкое значение, приводящее к тому, что буферы ввода-вывода становятся меньше 8 КБ; точная нижняя граница для этого зависит от размера построенных данных. Если буферы меньше 256 КБ, будет выдано предупреждение.
Максимально возможный лимит — 2047M. Слишком низкие значения могут снизить скорость построения простых таблиц, но 256M–1024M должно быть достаточно для большинства, если не для всех наборов данных. Установка слишком высокого значения может вызвать таймауты SQL-сервера. Во время фазы сбора документов будут периоды, когда буфер памяти частично сортируется и связь с базой данных не выполняется; и сервер базы данных может превысить время ожидания. Это можно решить либо увеличением таймаутов на стороне SQL-сервера, либо уменьшением mem_limit.
on_file_field_error = skip_document
Как обрабатывать ошибки ввода-вывода в файловых полях. Необязательный параметр, по умолчанию ignore_field.
При возникновении проблемы с индексацией файла, на который ссылается файловое поле (sql_file_field), indexer может либо обработать документ, предполагая пустое содержимое в этом конкретном поле, либо пропустить документ, либо полностью завершить индексацию с ошибкой. Директива on_file_field_error управляет этим поведением. Принимаемые значения:
ignore_field, обработать текущий документ без поля;skip_document, пропустить текущий документ, но продолжить индексацию;fail_index, завершить индексацию с сообщением об ошибке.
Возможные проблемы: ошибка открытия, ошибка размера (файл слишком большой) и ошибка чтения данных. Предупреждающие сообщения о любой проблеме будут выдаваться всегда, независимо от фазы и настройки on_file_field_error.
Обратите внимание, что при on_file_field_error = skip_document документы будут игнорироваться только в том случае, если проблемы обнаружены на ранней фазе проверки, и не во время фактической фазы разбора файла. indexer откроет каждый указанный файл и проверит его размер перед началом работы, а затем откроет его снова при выполнении фактической работы по разбору. Поэтому, если файл исчезнет между этими двумя попытками открытия, документ все равно будет проиндексирован.
write_buffer = 4M
Размер буфера записи, байты. Необязательный параметр, по умолчанию 1 МБ. Буферы записи используются для записи как временных, так и окончательных файлов таблиц при индексации. Более крупные буферы уменьшают количество необходимых операций записи на диск. Память для буферов выделяется дополнительно к mem_limit. Обратите внимание, что будет выделено несколько (в настоящее время до 4) буферов для разных файлов, что пропорционально увеличит использование оперативной памяти.
ignore_non_plain = 1
ignore_non_plain позволяет полностью игнорировать предупреждения о пропуске непростых таблиц. По умолчанию 0 (не игнорировать).
Существует два подхода к планированию запусков indexer. Первый способ — классический метод использования crontab. Второй способ — использование таймера systemd с пользовательским расписанием. Чтобы создать файлы юнитов таймера, их следует поместить в соответствующий каталог, где systemd ищет такие файлы юнитов. В большинстве дистрибутивов Linux этот каталог обычно /etc/systemd/system. Вот как это сделать:
-
Создайте файл юнита таймера для вашего пользовательского расписания:
cat << EOF > /etc/systemd/system/manticore-indexer@.timer [Unit] Description=Run Manticore Search's indexer on schedule [Timer] OnCalendar=minutely RandomizedDelaySec=5m Unit=manticore-indexer@%i.service [Install] WantedBy=timers.target EOFПодробнее о синтаксисе
OnCalendarи примерах можно узнать здесь. -
Отредактируйте юнит таймера в соответствии с вашими потребностями.
-
Включите таймер:
systemctl enable manticore-indexer@idx1.timer -
Запустите таймер:
systemctl start manticore-indexer@idx1.timer -
Повторите шаги 2–4 для любых дополнительных таймеров.