Если вы ищете информацию о добавлении документов в обычную таблицу, пожалуйста, обратитесь к разделу о добавлении данных из внешних хранилищ.
Добавление документов в реальном времени поддерживается только для таблиц Real-Time и percolate. Соответствующая SQL-команда, HTTP-эндпоинт или клиентские функции вставляют новые строки (документы) в таблицу с указанными значениями полей. Таблица не обязательно должна существовать до добавления в неё документов. Если таблица не существует, Manticore попытается создать её автоматически. Для получения дополнительной информации смотрите Автоматическая схема.
Вы можете вставить один или несколько документов с значениями для всех полей таблицы или только для части из них. В этом случае остальные поля будут заполнены значениями по умолчанию (0 для скалярных типов, пустая строка для текстовых типов).
В INSERT выражения в настоящее время не поддерживаются, поэтому значения должны быть указаны явно.
Поле/значение ID может быть опущено, так как таблицы RT и PQ поддерживают функциональность auto-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 не поддерживает автоматическое создание таблиц (auto schema). Только 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) поддерживает Chunked transfer encoding. Вы можете использовать это для передачи больших партий. Это:
- снижает пиковое использование оперативной памяти, уменьшая риск 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;В таблице перколяции хранятся документы, которые являются правилами запроса перколяции и должны строго соответствовать схеме из четырёх полей:
| поле | тип | описание |
|---|---|---|
| id | bigint | идентификатор правила PQ (если не указан, будет назначен автоматически) |
| query | string | полнотекстовый запрос (может быть пустым), совместимый с таблицей перколяции |
| filters | string | дополнительные фильтры по полям, не являющимся полнотекстовыми (может быть пустым), совместимые с таблицей перколяции |
| tags | string | строка с одним или несколькими тегами, разделёнными запятыми, которые могут использоваться для выборочного отображения/удаления сохранённых запросов |
Любые другие имена полей не поддерживаются и вызовут ошибку.
Внимание: Вставка/замена правил PQ в формате JSON через SQL не сработает. Другими словами, операторы, специфичные для JSON (match и т.п.), будут рассматриваться просто как части текста правила, которые должны совпадать с документами. Если вы предпочитаете синтаксис JSON, используйте HTTP-эндпоинт вместо 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;Существует два способа добавить запрос перколяции в таблицу перколяции:
-
Запрос в формате JSON, совместимом с /search, описанном в json/search
PUT /pq/pq_table/doc/1 { "query": { "match": { "title": "shoes" }, "range": { "price": { "gt": 5 } } }, "tags": ["Loius Vuitton"] } -
Запрос в формате SQL, описанном в синтаксисе запросов search
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 из внешних хранилищ с помощью различных методов:
- Инструмент Indexer для получения данных из различных баз данных в plain-таблицы.
- Интеграции Logstash, Filebeat и Vector.dev для передачи данных в real-time таблицы Manticore из этих инструментов.
- Интеграция Kafka для синхронизации данных из тем Kafka в real-time таблицу.
Простые таблицы — это таблицы, которые создаются однократно путём получения данных при создании из одного или нескольких источников. Простая таблица является неизменяемой, так как документы не могут быть добавлены или удалены в течение её жизненного цикла. Возможно только обновление значений числовых атрибутов (включая 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 с помощью следующего файла юнита 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задает максимальное количество слов в списке. Если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В приведенном примере, где main — это основная, редко изменяемая таблица, а delta — более часто изменяемая, вы можете использовать эту команду для вызова
indexer, чтобы объединить содержимое delta с main и выполнить ротацию таблиц. -
--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) изменяет способ обработки списков удаления (kill lists) при слиянии таблиц. По умолчанию оба списка удаления отбрасываются после слияния. Это поддерживает наиболее типичный сценарий слияния main+delta. При включении этой опции списки удаления обеих таблиц объединяются и сохраняются в целевой таблице. Обратите внимание, что список удаления исходной (delta) таблицы всегда используется для подавления строк из целевой (main) таблицы. -
--keep-attrsпозволяет повторно использовать существующие атрибуты при переиндексации. При перестроении таблицы для каждого нового id документа проверяется наличие в "старой" таблице, и если он уже существует, его атрибуты переносятся в "новую" таблицу; если не найден, используются атрибуты из новой таблицы. Если пользователь обновил атрибуты в таблице, но не в исходных данных, используемых для таблицы, все обновления будут потеряны при переиндексации; использование--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. MVAs не поддерживаются. -
--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 позволяет контролировать, сколько именно RAM может быть выделено для этого кэша распакованного словаря.
В настоящее время доступны только словари ru.pak, en.pak и de.pak. Это русские, английские и немецкие словари. Размер сжатого словаря примерно от 2 до 10 МБ. Обратите внимание, что словарь всегда находится в памяти. Размер кэша по умолчанию — 256 КБ. Допустимые размеры кэша — от 0 до 2047 МБ. Безопасно увеличивать размер кэша слишком высоко; лемматизатор будет использовать только необходимую память. Например, весь русский словарь распаковывается примерно до 110 МБ; поэтому установка lemmatizer_cache выше этого значения не повлияет на использование памяти. Даже если разрешено 1024 МБ для кэша, если нужно только 110 МБ, будет использовано только 110 МБ.
max_file_field_buffer = 128M
Максимальный размер адаптивного буфера для файлового поля в байтах. Необязательно, по умолчанию 8 МБ, минимум 1 МБ.
Буфер файлового поля используется для загрузки файлов, на которые ссылаются столбцы 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 может вызывать всплески интенсивных операций дискового ввода-вывода во время построения таблицы, и может быть желательно ограничить его активность на диске (и оставить ресурсы для других программ, работающих на той же машине, например searchd). Ограничение I/O помогает в этом. Оно работает, обеспечивая минимальную гарантированную задержку между последовательными операциями дискового ввода-вывода, выполняемыми indexer. Ограничение I/O может помочь уменьшить ухудшение производительности поиска, вызванное построением. Эта настройка неэффективна для других видов загрузки данных, например вставки данных в таблицу реального времени.
max_iosize = 1048576
Максимально допустимый размер операции ввода-вывода в байтах для ограничения I/O. Необязательно, по умолчанию 0 (без ограничений).
Опция, связанная с ограничением I/O. Она ограничивает максимальный размер файловой операции ввода-вывода (чтение или запись) для всех операций, выполняемых indexer. Значение 0 означает отсутствие ограничений. Чтения или записи, превышающие этот лимит, будут разбиты на несколько меньших операций и учитываться как несколько операций в настройке max_iops. На момент написания все вызовы I/O должны быть меньше 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
Plain table building RAM usage limit. Optional, default is 128 MB. Enforced memory usage limit that the indexer will not go above. Can be specified in bytes, or kilobytes (using K postfix), or megabytes (using M postfix); see the example. This limit will be automatically raised if set to an extremely low value causing I/O buffers to be less than 8 KB; the exact lower bound for that depends on the built data size. If the buffers are less than 256 KB, a warning will be produced.
Максимально возможный лимит — 2047M. Слишком низкие значения могут замедлить построение plain table, но 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
Размер буфера записи, в байтах. Необязательно, по умолчанию 1MB. Буферы записи используются для записи как временных, так и окончательных файлов таблиц при индексировании. Большие буферы уменьшают количество необходимых операций записи на диск. Память для буферов выделяется дополнительно к mem_limit. Обратите внимание, что будет выделено несколько (в настоящее время до 4) буферов для разных файлов, что пропорционально увеличивает использование ОЗУ.
ignore_non_plain = 1
ignore_non_plain позволяет полностью игнорировать предупреждения о пропуске не-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 для любых дополнительных таймеров.