WHERE — это SQL-клауза, которая работает как для полнотекстового поиска, так и для дополнительной фильтрации. Доступны следующие операторы:
- Операторы сравнения
<, >, <=, >=, =, <>, BETWEEN, IN, IS NULL - Логические операторы
AND, OR, NOT
Поддерживается MATCH('query'), который соответствует полнотекстовому запросу.
Поддерживается синтаксис условия {col_name | expr_alias} [NOT] IN @uservar. Описание глобальных пользовательских переменных см. в синтаксисе SET.
Если вы предпочитаете интерфейс HTTP JSON, вы также можете применять фильтрацию. Он может показаться более сложным, чем SQL, но рекомендуется для случаев, когда вам нужно программно подготовить запрос, например, когда пользователь заполняет форму в вашем приложении.
Вот пример нескольких фильтров в запросе bool.
Этот полнотекстовый запрос соответствует всем документам, содержащим product в любом поле. Эти документы должны иметь цену больше или равную 500 (gte) и меньше или равную 1000 (lte). Все эти документы не должны иметь ревизию меньше 15 (lt).
- JSON
POST /search
{
"table": "test1",
"query": {
"bool": {
"must": [
{ "match" : { "_all" : "product" } },
{ "range": { "price": { "gte": 500, "lte": 1000 } } }
],
"must_not": {
"range": { "revision": { "lt": 15 } }
}
}
}
}Запрос bool сопоставляет документы на основе логических комбинаций других запросов и/или фильтров. Запросы и фильтры должны быть указаны в разделах must, should или must_not и могут быть вложенными.
- JSON
POST /search
{
"table":"test1",
"query": {
"bool": {
"must": [
{ "match": {"_all":"keyword"} },
{ "range": { "revision": { "gte": 14 } } }
]
}
}
}Запросы и фильтры, указанные в разделе must, должны соответствовать документам. Если указано несколько полнотекстовых запросов или фильтров, все они должны соответствовать. Это эквивалентно запросам AND в SQL. Обратите внимание, что если вы хотите сопоставить с массивом (многозначный атрибут), вы можете указать атрибут несколько раз. Результат будет положительным только если все запрошенные значения найдены в массиве, например:
"must": [
{"equals" : { "product_codes": 5 }},
{"equals" : { "product_codes": 6 }}
]
Также обратите внимание, что с точки зрения производительности может быть лучше использовать:
{"in" : { "all(product_codes)": [5,6] }}
(подробности ниже).
Запросы и фильтры, указанные в разделе should, должны соответствовать документам. Если некоторые запросы указаны в must или must_not, запросы should игнорируются. С другой стороны, если нет других запросов, кроме should, то хотя бы один из этих запросов должен соответствовать документу, чтобы он соответствовал bool-запросу. Это эквивалент запросов OR. Обратите внимание, если вы хотите сопоставить с массивом (многозначный атрибут) вы можете указать атрибут несколько раз, например:
"should": [
{"equals" : { "product_codes": 7 }},
{"equals" : { "product_codes": 8 }}
]
Также обратите внимание, что с точки зрения производительности может быть лучше использовать:
{"in" : { "any(product_codes)": [7,8] }}
(подробности ниже).
Запросы и фильтры, указанные в разделе must_not, не должны соответствовать документам. Если несколько запросов указано в must_not, документ соответствует, если ни один из них не соответствует.
- JSON
POST /search
{
"table":"t",
"query": {
"bool": {
"should": [
{
"equals": {
"b": 1
}
},
{
"equals": {
"b": 3
}
}
],
"must": [
{
"equals": {
"a": 1
}
}
],
"must_not": {
"equals": {
"b": 2
}
}
}
}
}Bool-запрос может быть вложен в другой bool-запрос, чтобы вы могли создавать более сложные запросы. Чтобы сделать вложенный логический запрос, просто используйте другой bool вместо must, should или must_not. Вот как этот запрос:
a = 2 and (a = 10 or b = 0)
должен быть представлен в JSON.
- JSON
a = 2 and (a = 10 or b = 0)
POST /search
{
"table":"t",
"query": {
"bool": {
"must": [
{
"equals": {
"a": 2
}
},
{
"bool": {
"should": [
{
"equals": {
"a": 10
}
},
{
"equals": {
"b": 0
}
}
]
}
}
]
}
}
}Более сложный запрос:
(a = 1 and b = 1) or (a = 10 and b = 2) or (b = 0)
- JSON
(a = 1 and b = 1) or (a = 10 and b = 2) or (b = 0)
POST /search
{
"table":"t",
"query": {
"bool": {
"should": [
{
"bool": {
"must": [
{
"equals": {
"a": 1
}
},
{
"equals": {
"b": 1
}
}
]
}
},
{
"bool": {
"must": [
{
"equals": {
"a": 10
}
},
{
"equals": {
"b": 2
}
}
]
}
},
{
"bool": {
"must": [
{
"equals": {
"b": 0
}
}
]
}
}
]
}
}
}Запросы в формате SQL (query_string) также могут использоваться в bool-запросах.
- JSON
POST /search
{
"table": "test1",
"query": {
"bool": {
"must": [
{ "query_string" : "product" },
{ "query_string" : "good" }
]
}
}
}Фильтры равенства — это простейшие фильтры, которые работают с целочисленными, вещественными и строковыми атрибутами.
- JSON
POST /search
{
"table":"test1",
"query": {
"equals": { "price": 500 }
}
}Фильтр equals может быть применен к многозначному атрибуту и вы можете использовать:
any(), который будет положительным, если атрибут имеет хотя бы одно значение, равное запрошенному;all(), который будет положительным, если атрибут имеет единственное значение и оно равно запрошенному
- JSON
POST /search
{
"table":"test1",
"query": {
"equals": { "any(price)": 100 }
}
}Фильтры множества проверяют, равно ли значение атрибута любому из значений в указанном множестве.
Фильтры множества поддерживают целочисленные, строковые и многозначные атрибуты.
- JSON
POST /search
{
"table":"test1",
"query": {
"in": {
"price": [1,10,100]
}
}
}При применении к многозначному атрибуту вы можете использовать:
any()(эквивалентно отсутствию функции), который будет положительным, если есть хотя бы одно совпадение между значениями атрибута и запрошенными значениями;all(), который будет положительным, если все значения атрибута находятся в запрошенном множестве
- JSON
POST /search
{
"table":"test1",
"query": {
"in": {
"all(price)": [1,10]
}
}
}Фильтры диапазона сопоставляют документы, у которых значения атрибутов находятся в указанном диапазоне.
Фильтры диапазона поддерживают следующие свойства:
gte: больше или равноgt: большеlte: меньше или равноlt: меньше
- JSON
POST /search
{
"table":"test1",
"query": {
"range": {
"price": {
"gte": 500,
"lte": 1000
}
}
}
}Фильтры geo_distance используются для фильтрации документов, которые находятся в пределах определенного расстояния от географического местоположения.
Указывает точку привязки, в градусах. Расстояния рассчитываются от этой точки.
Указывает атрибуты, содержащие широту и долготу.
Указывает функцию расчета расстояния. Может быть adaptive или haversine. adaptive быстрее и точнее, подробности см. в GEODIST(). Необязательный параметр, по умолчанию adaptive.
Определяет максимальное расстояние от местоположения точек привязки. Все документы в пределах этого расстояния считаются соответствующими. Расстояние может быть указано в различных единицах измерения. Если единица измерения не указана, расстояние считается в метрах. Вот список поддерживаемых единиц измерения расстояния:
- Метр:
mилиmeters - Километр:
kmилиkilometers - Сантиметр:
cmилиcentimeters - Миллиметр:
mmилиmillimeters - Миля:
miилиmiles - Ярд:
ydилиyards - Фут:
ftилиfeet - Дюйм:
inилиinch - Морская миля:
NM,nmiилиnauticalmiles
Свойства location_anchor и location_source принимают следующие форматы широты/долготы:
- объект с ключами lat и lon:
{ "lat": "attr_lat", "lon": "attr_lon" } - строка следующей структуры:
"attr_lat, attr_lon" - массив с широтой и долготой в следующем порядке:
[attr_lon, attr_lat]
Широта и долгота указываются в градусах.
- Basic example
- Advanced example
POST /search
{
"table":"test",
"query": {
"geo_distance": {
"location_anchor": {"lat":49, "lon":15},
"location_source": {"attr_lat, attr_lon"},
"distance_type": "adaptive",
"distance":"100 km"
}
}
}geo_distance может использоваться в качестве фильтра в bool-запросах вместе с matches или другими фильтрами атрибутов.
POST /search
{
"table": "geodemo",
"query": {
"bool": {
"must": [
{
"match": {
"*": "station"
}
},
{
"equals": {
"state_code": "ENG"
}
},
{
"geo_distance": {
"distance_type": "adaptive",
"location_anchor": {
"lat": 52.396,
"lon": -1.774
},
"location_source": "latitude_deg,longitude_deg",
"distance": "10000 m"
}
}
]
}
}
}Объединения таблиц в Manticore Search позволяют комбинировать документы из двух таблиц путем сопоставления связанных столбцов. Эта функциональность обеспечивает более сложные запросы и улучшенный поиск данных по нескольким таблицам.
SELECT
select_expr [, select_expr] ...
FROM tbl_name
{INNER | LEFT} JOIN tbl2_name
ON join_condition
[...other select options]
join_condition: {
left_table.attr = right_table.attr
| left_table.json_attr.string_id = string(right_table.json_attr.string_id)
| left_table.json_attr.int_id = int(right_table.json_attr.int_id)
| [..filters on right table attributes]
}
Для получения дополнительной информации о параметрах select смотрите раздел SELECT.
При объединении по значению из JSON-атрибута необходимо явно указать тип значения с помощью функции int() или string().
SELECT ... ON left_table.json_attr.string_id = string(right_table.json_attr.string_id)
SELECT ... ON left_table.json_attr.int_id = int(right_table.json_attr.int_id)
POST /search
{
"table": "table_name",
"query": {
<optional full-text query against the left table>
},
"join": [
{
"type": "inner" | "left",
"table": "joined_table_name",
"query": {
<optional full-text query against the right table>
},
"on": [
{
"left": {
"table": "left_table_name",
"field": "field_name",
"type": "<common field's type when joining using json attributes>"
},
"operator": "eq",
"right": {
"table": "right_table_name",
"field": "field_name"
}
}
]
}
],
"options": {
...
}
}
on.type: {
int
| string
}
Обратите внимание, что в разделе операнда left есть поле type, которое следует использовать при объединении двух таблиц с использованием json-атрибутов. Допустимые значения — string и int.
Manticore Search поддерживает два типа объединений:
- INNER JOIN: Возвращает только те строки, где есть совпадение в обеих таблицах. Например, запрос выполняет INNER JOIN между таблицами
ordersиcustomers, включая только заказы, у которых есть соответствующие клиенты.
- SQL
- JSON
SELECT product, customers.email, customers.name, customers.address
FROM orders
INNER JOIN customers
ON customers.id = orders.customer_id
WHERE MATCH('maple', customers)
ORDER BY customers.email ASC;POST /search
{
"table": "orders",
"join": [
{
"type": "inner",
"table": "customers",
"query": {
"query_string": "maple"
},
"on": [
{
"left": {
"table": "orders",
"field": "customer_id"
},
"operator": "eq",
"right": {
"table": "customers",
"field": "id"
}
}
]
}
],
"_source": ["product", "customers.email", "customers.name", "customers.address"],
"sort": [{"customers.email": "asc"}]
}+---------+-------------------+----------------+-------------------+
| product | customers.email | customers.name | customers.address |
+---------+-------------------+----------------+-------------------+
| Laptop | alice@example.com | Alice Johnson | 123 Maple St |
| Tablet | alice@example.com | Alice Johnson | 123 Maple St |
+---------+-------------------+----------------+-------------------+
2 rows in set (0.00 sec){
"took": 0,
"timed_out": false,
"hits": {
"total": 2,
"total_relation": "eq",
"hits": [
{
"_id": 1,
"_score": 1,
"_source": {
"product": "Laptop",
"customers.email": "alice@example.com",
"customers.name": "Alice Johnson",
"customers.address": "123 Maple St"
}
},
{
"_id": 3,
"_score": 1,
"_source": {
"product": "Tablet",
"customers.email": "alice@example.com",
"customers.name": "Alice Johnson",
"customers.address": "123 Maple St"
}
}
]
}
}- LEFT JOIN: Возвращает все строки из левой таблицы и соответствующие строки из правой таблицы. Если совпадения нет, то для столбцов правой таблицы возвращаются значения NULL. Например, этот запрос извлекает всех клиентов вместе с их заказами с использованием LEFT JOIN. Если соответствующий заказ отсутствует, появятся значения NULL. Результаты сортируются по электронной почте клиента, и выбираются только имя клиента и количество заказов.
- SQL
- JSON
SELECT
name, orders.quantity
FROM customers
LEFT JOIN orders
ON orders.customer_id = customers.id
ORDER BY email ASC;POST /search
{
"table": "customers",
"_source": ["name", "orders.quantity"],
"join": [
{
"type": "left",
"table": "orders",
"on": [
{
"left": {
"table": "orders",
"field": "customer_id"
},
"operator": "eq",
"right": {
"table": "customers",
"field": "id"
}
}
]
}
],
"sort": [{"email": "asc"}]
}+---------------+-----------------+-------------------+
| name | orders.quantity | @int_attr_email |
+---------------+-----------------+-------------------+
| Alice Johnson | 1 | alice@example.com |
| Alice Johnson | 1 | alice@example.com |
| Bob Smith | 2 | bob@example.com |
| Carol White | 1 | carol@example.com |
| John Smith | NULL | john@example.com |
+---------------+-----------------+-------------------+
5 rows in set (0.00 sec){
"took": 0,
"timed_out": false,
"hits": {
"total": 5,
"total_relation": "eq",
"hits": [
{
"_id": 1,
"_score": 1,
"_source": {
"name": "Alice Johnson",
"address": "123 Maple St",
"email": "alice@example.com",
"orders.id": 3,
"orders.customer_id": 1,
"orders.quantity": 1,
"orders.order_date": "2023-01-03",
"orders.tags": [
101,
104
],
"orders.details": {
"price": 450,
"warranty": "1 year"
},
"orders.product": "Tablet"
}
},
{
"_id": 1,
"_score": 1,
"_source": {
"name": "Alice Johnson",
"address": "123 Maple St",
"email": "alice@example.com",
"orders.id": 1,
"orders.customer_id": 1,
"orders.quantity": 1,
"orders.order_date": "2023-01-01",
"orders.tags": [
101,
102
],
"orders.details": {
"price": 1200,
"warranty": "2 years"
},
"orders.product": "Laptop"
}
},
{
"_id": 2,
"_score": 1,
"_source": {
"name": "Bob Smith",
"address": "456 Oak St",
"email": "bob@example.com",
"orders.id": 2,
"orders.customer_id": 2,
"orders.quantity": 2,
"orders.order_date": "2023-01-02",
"orders.tags": [
103
],
"orders.details": {
"price": 800,
"warranty": "1 year"
},
"orders.product": "Phone"
}
},
{
"_id": 3,
"_score": 1,
"_source": {
"name": "Carol White",
"address": "789 Pine St",
"email": "carol@example.com",
"orders.id": 4,
"orders.customer_id": 3,
"orders.quantity": 1,
"orders.order_date": "2023-01-04",
"orders.tags": [
105
],
"orders.details": {
"price": 300,
"warranty": "1 year"
},
"orders.product": "Monitor"
}
},
{
"_id": 4,
"_score": 1,
"_source": {
"name": "John Smith",
"address": "15 Barclays St",
"email": "john@example.com",
"orders.id": 0,
"orders.customer_id": 0,
"orders.quantity": 0,
"orders.order_date": "",
"orders.tags": [],
"orders.details": null,
"orders.product": ""
}
}
]
}
}Одна из мощных возможностей объединений таблиц в Manticore Search — это возможность выполнять полнотекстовый поиск одновременно по левой и правой таблицам. Это позволяет создавать сложные запросы с фильтрацией на основе текстового содержимого в нескольких таблицах.
Вы можете использовать отдельные функции MATCH() для каждой таблицы в запросе JOIN. Запрос фильтрует результаты на основе текстового содержимого в обеих таблицах.
- SQL
- JSON
SELECT t1.f, t2.f
FROM t1
LEFT JOIN t2 ON t1.id = t2.id
WHERE MATCH('hello', t1) AND MATCH('goodbye', t2);POST /search
{
"table": "t1",
"query": {
"query_string": "hello"
},
"join": [
{
"type": "left",
"table": "t2",
"query": {
"query_string": "goodbye"
},
"on": [
{
"left": {
"table": "t1",
"field": "id"
},
"operator": "eq",
"right": {
"table": "t2",
"field": "id"
}
}
]
}
],
"_source": ["f", "t2.f"]
}+-------------+---------------+
| f | t2.f |
+-------------+---------------+
| hello world | goodbye world |
+-------------+---------------+
1 row in set (0.00 sec){
"took": 1,
"timed_out": false,
"hits": {
"total": 1,
"total_relation": "eq",
"hits": [
{
"_id": 2,
"_score": 1680,
"t2._score": 1680,
"_source": {
"f": "hello world",
"t2.f": "goodbye world"
}
}
]
}
}В запросах JSON API полнотекстовый поиск, специфичный для таблицы, организован иначе, чем в SQL:
Запрос главной таблицы: Поле "query" на корневом уровне применяется к главной таблице (указанной в "table").
Запрос присоединенной таблицы: В каждом определении объединения может быть свое поле "query", которое применяется конкретно к этой присоединенной таблице.
- JSON
POST /search
{
"table": "t1",
"query": {
"query_string": "hello"
},
"join": [
{
"type": "left",
"table": "t2",
"query": {
"match": {
"*": "goodbye"
}
},
"on": [
{
"left": {
"table": "t1",
"field": "id"
},
"operator": "eq",
"right": {
"table": "t2",
"field": "id"
}
}
]
}
]
}{
"took": 1,
"timed_out": false,
"hits": {
"total": 1,
"total_relation": "eq",
"hits": [
{
"_id": 1,
"_score": 1680,
"t2._score": 1680,
"_source": {
"f": "hello world",
"t2.id": 1,
"t2.f": "goodbye world"
}
}
]
}
}1. Запрос только к главной таблице: Возвращает все совпадающие строки из главной таблицы. Для не совпавших связанных записей (LEFT JOIN), SQL возвращает значения NULL, тогда как JSON API возвращает значения по умолчанию (0 для чисел, пустые строки для текста).
- SQL
- JSON
SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
WHERE MATCH('database', t1);POST /search
{
"table": "t1",
"query": {
"query_string": "database"
},
"join": [
{
"type": "left",
"table": "t2",
"on": [
{
"left": {
"table": "t1",
"field": "id"
},
"operator": "eq",
"right": {
"table": "t2",
"field": "id"
}
}
]
}
]
}+------+-----------------+-------+------+
| id | f | t2.id | t2.f |
+------+-----------------+-------+------+
| 3 | database search | NULL | NULL |
+------+-----------------+-------+------+
1 row in set (0.00 sec){
"took": 0,
"timed_out": false,
"hits": {
"total": 1,
"total_relation": "eq",
"hits": [
{
"_id": 3,
"_score": 1680,
"t2._score": 0,
"_source": {
"f": "database search",
"t2.id": 0,
"t2.f": ""
}
}
]
}
}2. Запрос к присоединенной таблице действует как фильтр: Когда у присоединенной таблицы есть запрос, возвращаются только записи, которые удовлетворяют и условию объединения, и условию запроса.
- JSON
POST /search
{
"table": "t1",
"query": {
"query_string": "database"
},
"join": [
{
"type": "left",
"table": "t2",
"query": {
"query_string": "nonexistent"
},
"on": [
{
"left": {
"table": "t1",
"field": "id"
},
"operator": "eq",
"right": {
"table": "t2",
"field": "id"
}
}
]
}
]
}{
"took": 0,
"timed_out": false,
"hits": {
"total": 0,
"total_relation": "eq",
"hits": []
}
}3. Тип JOIN влияет на фильтрацию: INNER JOIN требует удовлетворения как условия объединения, так и запроса, а LEFT JOIN возвращает совпадающие строки левой таблицы даже при несоответствии условий правой таблицы.
При использовании полнотекстового поиска с объединениями учитывайте следующие моменты:
-
Поиск специфичный для таблицы:
- SQL: каждая функция
MATCH()должна указывать, в какой таблице искать:MATCH('term', table_name) - JSON: используйте уровень
"query"для главной таблицы и"query"внутри каждого определения соединения для присоединенных таблиц
- SQL: каждая функция
-
Гибкость синтаксиса запроса: JSON API поддерживает синтаксисы
"query_string"и"match"для полнотекстовых запросов -
Влияние на производительность: Полнотекстовый поиск по обеим таблицам может повлиять на производительность, особенно при больших объемах данных. Рассмотрите использование соответствующих индексов и размеров пакетов.
-
Обработка NULL/значений по умолчанию: При LEFT JOIN, если не найдено совпадающей записи в правой таблице, оптимизатор запроса решает, сначала ли выполнять условия полнотекстового поиска или фильтрации, исходя из производительности. SQL возвращает NULL, тогда как JSON API — значения по умолчанию (0 для чисел, пустые строки для текста).
-
Поведение фильтрации: Запросы к присоединенным таблицам действуют как фильтры — они ограничивают результаты записями, удовлетворяющими и условиям объединения, и условию запроса.
-
Поддержка полнотекстовых операторов: Все операторы полнотекстового поиска поддерживаются в JOIN-запросах, включая фразы, близость, поиск по полям, NEAR, кворум и расширенные операторы.
-
Расчет рейтинга: Каждая таблица сохраняет свой собственный рейтинг релевантности, доступный через
table_name.weight()в SQL илиtable_name._scoreв JSON-ответах.
На основе предыдущих примеров рассмотрим более сложный сценарий, где мы комбинируем объединения таблиц с фасетами и полнотекстовым поиском по нескольким таблицам. Это демонстрирует весь потенциал возможностей JOIN в Manticore с комплексной фильтрацией и агрегацией.
Этот запрос демонстрирует полнотекстовый поиск по таблицам customers и orders, объединенный с фильтрацией по диапазону и фасетированием. Он ищет клиентов с именами "Alice" или "Bob" и их заказы, содержащие "laptop", "phone" или "tablet" с ценой выше $500. Результаты упорядочены по ID заказа и сфасетированы по условиям гарантии.
- SQL
- JSON
SELECT orders.product, name, orders.details.price, orders.tags
FROM customers
LEFT JOIN orders ON customers.id = orders.customer_id
WHERE orders.details.price > 500
AND MATCH('laptop | phone | tablet', orders)
AND MATCH('alice | bob', customers)
ORDER BY orders.id ASC
FACET orders.details.warranty;POST /search
{
"table": "customers",
"query": {
"bool": {
"must": [
{
"range": {
"orders.details.price": {
"gt": 500
}
},
"query_string": "alice | bob"
]
}
},
"join": [
{
"type": "left",
"table": "orders",
"query": {
"query_string": "laptop | phone | tablet"
},
"on": [
{
"left": {
"table": "customers",
"field": "id"
},
"operator": "eq",
"right": {
"table": "orders",
"field": "customer_id"
}
}
]
}
],
"_source": ["orders.product", "name", "orders.details.price", "orders.tags"],
"sort": [{"orders.id": "asc"}],
"aggs": {
"warranty_facet": {
"terms": {
"field": "orders.details.warranty"
}
}
}
}+-----------------+---------------+----------------------+-------------+
| orders.product | name | orders.details.price | orders.tags |
+-----------------+---------------+----------------------+-------------+
| Laptop Computer | Alice Johnson | 1200 | 101,102 |
| Smart Phone | Bob Smith | 800 | 103 |
+-----------------+---------------+----------------------+-------------+
2 rows in set (0.00 sec)
+-------------------------+----------+
| orders.details.warranty | count(*) |
+-------------------------+----------+
| 2 years | 1 |
| 1 year | 1 |
+-------------------------+----------+
2 rows in set (0.00 sec){
"took": 0,
"timed_out": false,
"hits": {
"total": 3,
"total_relation": "eq",
"hits": [
{
"_id": 1,
"_score": 1,
"orders._score": 1565,
"_source": {
"name": "Alice Johnson",
"orders.tags": [
101,
102
],
"orders.product": "Laptop Computer"
}
},
{
"_id": 2,
"_score": 1,
"orders._score": 1565,
"_source": {
"name": "Bob Smith",
"orders.tags": [
103
],
"orders.product": "Smart Phone"
}
},
{
"_id": 1,
"_score": 1,
"orders._score": 1565,
"_source": {
"name": "Alice Johnson",
"orders.tags": [
101,
104
],
"orders.product": "Tablet Device"
}
}
]
},
"aggregations": {
"warranty_facet": {
"buckets": [
{
"key": "2 years",
"doc_count": 1
},
{
"key": "1 year",
"doc_count": 2
}
]
}
}
}Для запросов в объединении можно указать отдельные параметры: для левой таблицы и для правой таблицы. Синтаксис: OPTION(<table_name>) для SQL-запросов и один или несколько подобъектов в "options" для JSON-запросов.
Вот пример, как указать разные веса полей для полнотекстового запроса по правой таблице. Чтобы получить веса совпадений через SQL, используйте выражение <table_name>.weight().
В JSON-запросах этот вес представлен как <table_name>._score.
- SQL
- JSON
SELECT product, customers.email, customers.name, customers.address, customers.weight()
FROM orders
INNER JOIN customers
ON customers.id = orders.customer_id
WHERE MATCH('maple', customers)
OPTION(customers) field_weights=(address=1500);POST /search
{
"table": "orders",
"options": {
"customers": {
"field_weights": {
"address": 1500
}
}
},
"join": [
{
"type": "inner",
"table": "customers",
"query": {
"query_string": "maple"
},
"on": [
{
"left": {
"table": "orders",
"field": "customer_id"
},
"operator": "eq",
"right": {
"table": "customers",
"field": "id"
}
}
]
}
],
"_source": ["product", "customers.email", "customers.name", "customers.address"]
}+---------+-------------------+----------------+-------------------+--------------------+
| product | customers.email | customers.name | customers.address | customers.weight() |
+---------+-------------------+----------------+-------------------+--------------------+
| Laptop | alice@example.com | Alice Johnson | 123 Maple St | 1500680 |
| Tablet | alice@example.com | Alice Johnson | 123 Maple St | 1500680 |
+---------+-------------------+----------------+-------------------+--------------------+
2 rows in set (0.00 sec){
"took": 0,
"timed_out": false,
"hits": {
"total": 2,
"total_relation": "eq",
"hits": [
{
"_id": 1,
"_score": 1,
"customers._score": 15000680,
"_source": {
"product": "Laptop",
"customers.email": "alice@example.com",
"customers.name": "Alice Johnson",
"customers.address": "123 Maple St"
}
},
{
"_id": 3,
"_score": 1,
"customers._score": 15000680,
"_source": {
"product": "Tablet",
"customers.email": "alice@example.com",
"customers.name": "Alice Johnson",
"customers.address": "123 Maple St"
}
}
]
}
}При выполнении объединений таблиц Manticore Search обрабатывает результаты пакетами для оптимизации производительности и использования ресурсов. Вот как это работает:
-
Как работает пакетная обработка:
- Сначала выполняется запрос по левой таблице, и результаты накапливаются в пакет.
- Затем этот пакет используется как входные данные для запроса по правой таблице, который выполняется как единая операция.
- Такой подход минимизирует количество запросов, отправляемых к правой таблице, повышая эффективность.
-
Настройка размера пакета:
- Размер пакета можно настроить с помощью опции поиска
join_batch_size. - Он также настраивается в разделе
searchdконфигурационного файла. - Размер пакета по умолчанию —
1000, но вы можете увеличить или уменьшить его в зависимости от вашего случая использования. - Установка
join_batch_size=0полностью отключает пакетную обработку, что может быть полезно для отладки или специфических сценариев.
- Размер пакета можно настроить с помощью опции поиска
-
Соображения производительности:
- Увеличение размера пакета может улучшить производительность, сокращая количество запросов, выполняемых к правой таблице.
- Однако большие пакеты могут потреблять больше памяти, особенно для сложных запросов или больших наборов данных.
- Экспериментируйте с разными размерами пакетов, чтобы найти оптимальный баланс между производительностью и использованием ресурсов.
Для дальнейшей оптимизации операций объединения Manticore Search использует механизм кэширования для запросов, выполняемых по правой таблице. Вот что нужно знать:
-
Как работает кэширование:
- Каждый запрос к правой таблице определяется условиями
JOIN ON. - Если одни и те же условия
JOIN ONповторяются в нескольких запросах, результаты кэшируются и используются повторно. - Это позволяет избежать избыточных запросов и ускорить последующие операции объединения.
- Каждый запрос к правой таблице определяется условиями
-
Настройка размера кэша:
- Размер кэша объединений можно настроить с помощью опции join_cache_size в разделе
searchdконфигурационного файла. - Размер кэша по умолчанию —
20MB, но вы можете изменить его в зависимости от рабочей нагрузки и доступной памяти. - Установка
join_cache_size=0полностью отключает кэширование.
- Размер кэша объединений можно настроить с помощью опции join_cache_size в разделе
-
Соображения по памяти:
- Каждый поток поддерживает свой собственный кэш, поэтому общее использование памяти зависит от количества потоков и размера кэша.
- Убедитесь, что ваш сервер имеет достаточно памяти для размещения кэша, особенно в средах с высокой конкурентностью.
Распределенные таблицы, состоящие только из локальных таблиц, поддерживаются как с левой, так и с правой стороны запроса на объединение. Однако распределенные таблицы, включающие удаленные таблицы, не поддерживаются.
При использовании JOIN в Manticore Search учитывайте следующие моменты:
-
Выбор полей: При выборе полей из двух таблиц в JOIN не используйте префикс для полей из левой таблицы, но используйте префикс для полей из правой таблицы. Например:
SELECT field_name, right_table.field_name FROM ... -
Условия JOIN: Всегда явно указывайте имена таблиц в ваших условиях JOIN:
JOIN ON table_name.some_field = another_table_name.some_field -
Выражения с JOIN: При использовании выражений, объединяющих поля из обеих объединенных таблиц, присваивайте псевдоним результату выражения:
SELECT *, (nums2.n + 3) AS x, x * n FROM nums LEFT JOIN nums2 ON nums2.id = nums.num2_id -
Фильтрация по псевдонимам выражений: Вы не можете использовать псевдонимы для выражений, включающих поля из обеих таблиц, в предложении WHERE.
-
JSON-атрибуты: При объединении по JSON-атрибутам вы должны явно преобразовывать значения к соответствующему типу:
-- Correct: SELECT * FROM t1 LEFT JOIN t2 ON int(t1.json_attr.id) = t2.json_attr.id -- Incorrect: SELECT * FROM t1 LEFT JOIN t2 ON t1.json_attr.id = t2.json_attr.id -
Обработка NULL: Вы можете использовать условия IS NULL и IS NOT NULL для объединенных полей:
SELECT * FROM t1 LEFT JOIN t2 ON t1.id = t2.id WHERE t2.name IS NULL SELECT * FROM t1 LEFT JOIN t2 ON t1.id = t2.id WHERE t2.name IS NOT NULL -
Использование ANY с MVA: При использовании функции
ANY()с многозначными атрибутами в JOIN присваивайте псевдоним многозначному атрибуту из объединенной таблицы:SELECT *, t2.m AS alias FROM t LEFT JOIN t2 ON t.id = t2.t_id WHERE ANY(alias) IN (3, 5)
Следуя этим рекомендациям, вы можете эффективно использовать JOIN в Manticore Search для объединения данных из нескольких индексов и выполнения сложных запросов.
Manticore позволяет использовать произвольные арифметические выражения как через SQL, так и через HTTP, включая значения атрибутов, внутренние атрибуты (ID документа и вес релевантности), арифметические операции, несколько встроенных функций и пользовательских функций. Ниже приведен полный справочник для быстрого доступа.
+, -, *, /, %, DIV, MOD
Доступны стандартные арифметические операторы. Арифметические вычисления с использованием этих операторов могут выполняться в трех различных режимах:
- с использованием чисел с плавающей запятой одинарной точности 32-битного формата IEEE 754 (по умолчанию),
- с использованием знаковых 32-битных целых чисел,
- с использованием 64-битных знаковых целых чисел.
Парсер выражений автоматически переключается в режим целых чисел, если ни одна операция не приводит к значению с плавающей запятой. В противном случае используется режим с плавающей запятой по умолчанию. Например, a+b будет вычислено с использованием 32-битных целых чисел, если оба аргумента 32-битные целые; или с использованием 64-битных целых, если оба аргумента целые, но один из них 64-битный; или с плавающей запятой в остальных случаях. Однако a/b или sqrt(a) всегда будут вычисляться с плавающей запятой, поскольку эти операции возвращают нецелочисленные результаты. Чтобы этого избежать, можно использовать IDIV(a,b) или форму DIV b. Кроме того, a*b не будет автоматически преобразовываться в 64-битные, если аргументы 32-битные. Чтобы получить результат в 64-битах, используйте BIGINT(), но обратите внимание, что если присутствуют нецелочисленные операции, BIGINT() будет просто игнорироваться.
<, > <=, >=, =, <>
Операторы сравнения возвращают 1.0, если условие истинно, и 0.0 в противном случае. Например, (a=b)+3 дает 4, когда атрибут a равен атрибуту b, и 3, когда a не равен. В отличие от MySQL, операции равенства (т.е., операторы = и <>) включают небольшой порог равенства (по умолчанию 1e-6). Если разница между сравниваемыми значениями находится в пределах порога, они считаются равными.
Операторы BETWEEN и IN, в случае многозначных атрибутов, возвращают истинну, если хотя бы одно из значений удовлетворяет условию (аналогично ANY()). Оператор IN не поддерживает JSON-атрибуты. Оператор IS (NOT) NULL поддерживается только для JSON-атрибутов.
AND, OR, NOT
Логические операторы (AND, OR, NOT) ведут себя ожидаемо. Они ассоциативны слева и имеют самый низкий приоритет по сравнению с другими операторами. NOT имеет более высокий приоритет, чем AND и OR, но все же ниже, чем любой другой оператор. AND и OR имеют одинаковый приоритет, поэтому рекомендуется использовать скобки, чтобы избежать путаницы в сложных выражениях.
&, |
Эти операторы выполняют побитовое AND и OR соответственно. Операнды должны быть целочисленных типов.
- ABS()
- ALL()
- ANY()
- ATAN2()
- BIGINT()
- BITDOT()
- BM25F()
- CEIL()
- CONCAT()
- CONTAINS()
- COS()
- CRC32()
- DATE_HISTOGRAM()
- DATE_RANGE()
- DAY()
- DOUBLE()
- EXP()
- FIBONACCI()
- FLOOR()
- GEODIST()
- GEOPOLY2D()
- GREATEST()
- HOUR()
- HISTOGRAM()
- IDIV()
- IF()
- IN()
- INDEXOF()
- INTEGER()
- INTERVAL()
- LAST_INSERT_ID()
- LEAST()
- LENGTH()
- LN()
- LOG10()
- LOG2()
- MAX()
- MIN()
- MINUTE()
- MIN_TOP_SORTVAL()
- MIN_TOP_WEIGHT()
- MONTH()
- NOW()
- PACKEDFACTORS()
- POLY2D()
- POW()
- RAND()
- RANGE()
- REGEX()
- REMAP()
- SECOND()
- SIN()
- SINT()
- SQRT()
- SUBSTRING_INDEX()
- TO_STRING()
- UINT()
- YEAR()
- YEARMONTH()
- YEARMONTHDAY()
- WEIGHT()
В HTTP JSON интерфейсе выражения поддерживаются через script_fields и expressions.
{
"table": "test",
"query": {
"match_all": {}
}, "script_fields": {
"add_all": {
"script": {
"inline": "( gid * 10 ) | crc32(title)"
}
},
"title_len": {
"script": {
"inline": "crc32(title)"
}
}
}
}
В этом примере создаются два выражения: add_all и title_len. Первое выражение вычисляет ( gid * 10 ) | crc32(title) и сохраняет результат в атрибут add_all. Второе выражение вычисляет crc32(title) и сохраняет результат в атрибут title_len.
В настоящее время поддерживаются только inline выражения. Значение свойства inline (вычисляемое выражение) имеет тот же синтаксис, что и SQL выражения.
Имя выражения может быть использовано для фильтрации или сортировки.
- script_fields
{
"table":"movies_rt",
"script_fields":{
"cond1":{
"script":{
"inline":"actor_2_facebook_likes =296 OR movie_facebook_likes =37000"
}
},
"cond2":{
"script":{
"inline":"IF (IN (content_rating,'TV-PG','PG'),2, IF(IN(content_rating,'TV-14','PG-13'),1,0))"
}
}
},
"limit":10,
"sort":[
{
"cond2":"desc"
},
{
"actor_1_name":"asc"
},
{
"actor_2_name":"desc"
}
],
"profile":true,
"query":{
"bool":{
"must":[
{
"match":{
"*":"star"
}
},
{
"equals":{
"cond1":1
}
}
],
"must_not":[
{
"equals":{
"content_rating":"R"
}
}
]
}
}
}По умолчанию значения выражений включаются в массив _source результирующего набора. Если источник выборочный (см. Выбор источника), имя выражения может быть добавлено в параметр _source в запросе. Обратите внимание, имена выражений должны быть в нижнем регистре.
expressions — это альтернатива script_fields с более простым синтаксисом. Пример запроса добавляет два выражения и сохраняет результаты в атрибуты add_all и title_len. Обратите внимание, имена выражений должны быть в нижнем регистре.
- expressions
{
"table": "test",
"query": { "match_all": {} },
"expressions":
{
"add_all": "( gid * 10 ) | crc32(title)",
"title_len": "crc32(title)"
}
}SQL-предложение SELECT и HTTP-эндпоинт /search поддерживают ряд опций, которые можно использовать для тонкой настройки поведения поиска.
SQL:
SELECT ... [OPTION <optionname>=<value> [ , ... ]] [/*+ [NO_][ColumnarScan|DocidIndex|SecondaryIndex(<attribute>[,...])]] /*]
HTTP:
POST /search
{
"table" : "table_name",
"options":
{
"optionname": "value",
"optionname2": <value2>
}
}
- SQL
- JSON
SELECT * FROM test WHERE MATCH('@title hello @body world')
OPTION ranker=bm25, max_matches=3000,
field_weights=(title=10, body=3), agent_query_timeout=10000POST /search
{
"table" : "test",
"query": {
"match": {
"title": "hello"
},
"match": {
"body": "world"
}
},
"options":
{
"ranker": "bm25",
"max_matches": 3000,
"field_weights": {
"title": 10,
"body": 3
},
"agent_query_timeout": 10000
}
}+------+-------+-------+
| id | title | body |
+------+-------+-------+
| 1 | hello | world |
+------+-------+-------+
1 row in set (0.00 sec){
"took": 0,
"timed_out": false,
"hits": {
"total": 1,
"total_relation": "eq",
"hits": [
{
"_id": 1,
"_score": 10500,
"_source": {
"title": "hello",
"body": "world"
}
}
]
}
}Поддерживаемые опции:
Целое число. Включает или отключает гарантированную точность агрегации при выполнении групповых запросов в нескольких потоках. По умолчанию 0.
При выполнении группового запроса он может выполняться параллельно на обычной таблице с несколькими псевдошардами (если включен pseudo_sharding). Аналогичный подход работает на RT-таблицах. Каждый шард/чанк выполняет запрос, но количество групп ограничено max_matches. Если результирующие наборы из разных шардов/чанков содержат разные группы, подсчет групп и агрегаты могут быть неточными. Обратите внимание, что Manticore пытается увеличить max_matches до max_matches_increase_threshold на основе количества уникальных значений группирующего атрибута (полученных из вторичных индексов). Если это удается, потери точности не будет.
Однако, если количество уникальных значений группирующего атрибута велико, дальнейшее увеличение max_matches может быть не лучшей стратегией, так как это может привести к потере производительности и увеличению использования памяти. Установка accurate_aggregation в 1 заставляет групповые поиски выполняться в одном потоке, что решает проблему точности. Обратите внимание, что выполнение в одном потоке применяется только тогда, когда max_matches не может быть установлен достаточно высоким; в противном случае поиски с accurate_aggregation=1 все равно будут выполняться в нескольких потоках.
В целом, установка accurate_aggregation в 1 гарантирует точность подсчета групп и агрегатов в RT-таблицах и обычных таблицах с pseudo_sharding=1. Недостаток в том, что поиски будут выполняться медленнее, так как они будут вынуждены работать в одном потоке.
Однако, если у нас есть RT-таблица и обычная таблица, содержащие одни и те же данные, и мы выполняем запрос с accurate_aggregation=1, мы все равно можем получить разные результаты. Это происходит потому, что демон может выбрать разные настройки max_matches для RT-таблицы и обычной таблицы из-за настройки max_matches_increase_threshold.
Целое число. Максимальное время в миллисекундах ожидания завершения удаленных запросов, см. этот раздел.
0 или 1 (по умолчанию 1). boolean_simplify=1 включает упрощение запроса для ускорения его выполнения.
Эта опция также может быть установлена глобально в конфигурации searchd для изменения поведения по умолчанию для всех запросов. Опция на уровне запроса переопределит глобальную настройку.
Строка, пользовательский комментарий, который копируется в файл журнала запросов.
Целое число. Определяет максимальное количество совпадений для обработки. Если не установлено, Manticore автоматически выберет подходящее значение.
N = 0: Отключает ограничение на количество совпадений.N > 0: Указывает Manticore остановить обработку результатов, как только будет найденоNсоответствующих документов.- Не установлено: Manticore определяет порог автоматически.
Когда Manticore не может определить точное количество соответствующих документов, поле total_relation в метаинформации запроса будет показывать gte, что означает Больше или Равно. Это указывает, что фактическое количество совпадений составляет по меньшей мере указанное total_found (в SQL) или hits.total (в JSON). Когда количество точное, total_relation будет отображать eq.
Примечание: Использование cutoff в агрегационных запросах не рекомендуется, так как это может привести к неточным или неполным результатам.
- Example
Использование cutoff в агрегационных запросах может привести к некорректным или вводящим в заблуждение результатам, как показано в следующем примере:
drop table if exists t
--------------
Query OK, 0 rows affected (0.02 sec)
--------------
create table t(a int)
--------------
Query OK, 0 rows affected (0.04 sec)
--------------
insert into t(a) values(1),(2),(3),(1),(2),(3)
--------------
Query OK, 6 rows affected (0.00 sec)
--------------
select avg(a) from t option cutoff=1 facet a
--------------
+----------+
| avg(a) |
+----------+
| 1.000000 |
+----------+
1 row in set (0.00 sec)
--- 1 out of 1 results in 0ms ---
+------+----------+
| a | count(*) |
+------+----------+
| 1 | 1 |
+------+----------+
1 row in set (0.00 sec)
--- 1 out of 1 results in 0ms ---Сравните с тем же запросом без cutoff:
--------------
select avg(a) from t facet a
--------------
+----------+
| avg(a) |
+----------+
| 2.000000 |
+----------+
1 row in set (0.00 sec)
--- 1 out of 1 results in 0ms ---
+------+----------+
| a | count(*) |
+------+----------+
| 1 | 2 |
| 2 | 2 |
| 3 | 2 |
+------+----------+
3 rows in set (0.00 sec)
--- 3 out of 3 results in 0ms ---Целое число. По умолчанию 3500. Эта опция устанавливает порог, ниже которого количества, возвращаемые count distinct, гарантированно точны в пределах обычной таблицы.
Допустимые значения в диапазоне от 500 до 15500. Значения вне этого диапазона будут ограничены.
Когда эта опция установлена в 0, включается алгоритм, гарантирующий точные подсчеты. Этот алгоритм собирает пары {группа, значение}, сортирует их и периодически удаляет дубликаты. Результат — точные подсчеты в пределах обычной таблицы. Однако этот подход не подходит для наборов данных с высокой кардинальностью из-за высокого потребления памяти и медленного выполнения запроса.
Когда distinct_precision_threshold установлен в значение больше 0, Manticore использует другой алгоритм. Он загружает подсчеты в хеш-таблицу и возвращает размер таблицы. Если хеш-таблица становится слишком большой, ее содержимое перемещается в структуру данных HyperLogLog. На этом этапе подсчеты становятся приблизительными, поскольку HyperLogLog — это вероятностный алгоритм. Этот подход поддерживает фиксированное максимальное использование памяти на группу, но есть компромисс в точности подсчетов.
Точность HyperLogLog и порог преобразования из хеш-таблицы в HyperLogLog определяются настройкой distinct_precision_threshold. Важно использовать эту опцию с осторожностью, поскольку удвоение ее значения также удвоит максимальный объем памяти, необходимый для вычисления подсчетов. Максимальное использование памяти можно приблизительно оценить по формуле: 64 * max_matches * distinct_precision_threshold, хотя на практике вычисления подсчетов часто используют меньше памяти, чем в худшем случае.
0 или 1 (по умолчанию 0). Расширяет ключевые слова точными формами и/или звездочками, когда это возможно. Подробнее см. expand_keywords.
0, off, 1 или любая комбинация опций blend_mode (по умолчанию 0). Расширяет смешанные ключевые слова (токены, содержащие символы, настроенные через blend_chars) на их составные варианты во время разбора запроса. При включении ключевые слова, такие как "well-being" (если - настроен в blend_chars), расширяются в варианты, такие как "well-being", "wellbeing", "well" и "being", которые затем группируются в поддеревья ИЛИ в дереве запроса.
Поддерживаемые значения:
0илиoff- Расширение смешанных слов отключено (по умолчанию). Смешанные ключевые слова обрабатываются обычным образом без расширения.1- Расширение смешанных слов включено и использует настройку blend_mode таблицы для определения, какие варианты генерировать.- Любая опция(и) режима смешивания - Расширение смешанных слов включено с указанным режимом(ами) смешивания, переопределяя настройку
blend_modeтаблицы.
Подробнее об опциях см. blend_mode.
Именованный список целых чисел (пользовательские веса по полям для ранжирования).
Пример:
SELECT ... OPTION field_weights=(title=10, body=3)
Использовать глобальную статистику (частоты) из файла global_idf для вычислений IDF.
Заключенный в кавычки список флагов вычисления IDF, разделенных запятыми. Известные флаги:
normalized: вариант BM25, idf = log((N-n+1)/n), согласно Robertson et alplain: простой вариант, idf = log(N/n), согласно Sparck-Jonestfidf_normalized: дополнительно делить IDF на количество слов в запросе, чтобыTF*IDFпопадал в диапазон [0, 1]tfidf_unnormalized: не делить дополнительно IDF на количество слов в запросе, где N - размер коллекции, а n - количество совпадающих документов
Исторически используемый по умолчанию IDF (обратная частота документа) в Manticore эквивалентен OPTION idf='normalized,tfidf_normalized', и эти нормализации могут вызывать несколько нежелательных эффектов.
Во-первых, idf=normalized приводит к штрафованию ключевых слов. Например, если вы ищете the | something и the встречается более чем в 50% документов, то документы с обоими ключевыми словами the и something получат меньший вес, чем документы только с одним ключевым словом something. Использование OPTION idf=plain позволяет избежать этого. Простой IDF варьируется в диапазоне [0, log(N)], и ключевые слова никогда не штрафуются; в то время как нормализованный IDF варьируется в диапазоне [-log(N), log(N)], и слишком частые ключевые слова штрафуются.
Во-вторых, idf=tfidf_normalized приводит к смещению IDF между запросами. Исторически IDF также делился на количество ключевых слов в запросе, гарантируя, что вся sum(tf*idf) по всем ключевым словам остается в пределах диапазона [0,1]. Однако это означало, что запросы типа word1 и word1 | nonmatchingword2 присваивали разные веса одному и тому же набору результатов, поскольку IDF как для word1, так и для nonmatchingword2 делились на 2. Использование OPTION idf='tfidf_unnormalized' решает эту проблему. Имейте в виду, что факторы ранжирования BM25, BM25A, BM25F() будут соответствующим образом скорректированы при отключении этой нормализации.
Флаги IDF можно комбинировать; plain и normalized являются взаимоисключающими; tfidf_unnormalized и tfidf_normalized также являются взаимоисключающими; и неуказанные флаги в таких взаимоисключающих группах по умолчанию сохраняют свои исходные настройки. Это означает, что OPTION idf=plain эквивалентно полному указанию OPTION idf='plain,tfidf_normalized'.
Определяет режим сегментации Jieba для запроса.
При использовании китайской сегментации Jieba иногда может быть полезно использовать разные режимы сегментации для токенизации документов и запроса. Полный список режимов см. в jieba_mode.
Именованный список целых чисел. Пользовательские веса по таблицам для ранжирования.
0 или 1, автоматически суммировать DF по всем локальным частям распределенной таблицы, обеспечивая согласованные (и точные) IDF для локально шардированной таблицы. По умолчанию включено для дисковых чанков RT-таблицы. Термины запроса с подстановочными знаками игнорируются.
0 или 1 (по умолчанию 0). Установка low_priority=1 выполняет запрос с более низким приоритетом, перепланируя его задачи в 10 раз реже, чем другие запросы с обычным приоритетом.
Целое число. Значение максимального количества совпадений на запрос.
Максимальное количество совпадений, которое сервер хранит в оперативной памяти для каждой таблицы и может вернуть клиенту. По умолчанию равно 1000.
Введенная для контроля и ограничения использования оперативной памяти, настройка max_matches определяет, сколько совпадений будет храниться в оперативной памяти при поиске по каждой таблице. Каждое найденное совпадение все равно обрабатывается, но только лучшие N из них будут сохранены в памяти и в конечном итоге возвращены клиенту. Например, предположим, что таблица содержит 2 000 000 совпадений для запроса. Редко возникает необходимость получить их все. Вместо этого вам нужно просканировать их все, но выбрать только "лучшие" 500, например, на основе некоторых критериев (например, отсортированных по релевантности, цене или другим факторам) и отобразить эти 500 совпадений конечному пользователю страницами по 20-100 совпадений. Отслеживание только лучших 500 совпадений гораздо эффективнее по использованию оперативной памяти и процессора, чем хранение всех 2 000 000 совпадений, их сортировка, а затем отбрасывание всего, кроме первых 20, необходимых для страницы результатов поиска. max_matches контролирует N в этом количестве "лучших N".
Этот параметр значительно влияет на использование оперативной памяти и процессора для каждого запроса. Значения от 1 000 до 10 000 обычно приемлемы, но более высокие лимиты следует использовать с осторожностью. Бездумное увеличение max_matches до 1 000 000 означает, что searchd должен будет выделять и инициализировать буфер совпадений на 1 миллион записей для каждого запроса. Это неизбежно увеличит использование оперативной памяти на запрос и, в некоторых случаях, может заметно повлиять на производительность.
Обратитесь к max_matches_increase_threshold для получения дополнительной информации о том, как это может повлиять на поведение опции max_matches.
Целое число. Устанавливает порог, до которого можно увеличить max_matches. По умолчанию 16384.
Manticore может увеличить max_matches для повышения точности группировки и/или агрегации, когда включен pseudo_sharding, и если он обнаруживает, что количество уникальных значений атрибута группировки меньше этого порога. Потеря точности может произойти, когда псевдошардирование выполняет запрос в нескольких потоках или когда RT-таблица проводит параллельный поиск в дисковых чанках.
Если количество уникальных значений атрибута группировки меньше порога, max_matches будет установлено в это число. В противном случае будет использовано значение max_matches по умолчанию.
Если max_matches было явно установлено в параметрах запроса, этот порог не действует.
Имейте в виду, что если этот порог установлен слишком высоко, это приведет к увеличению потребления памяти и общему снижению производительности.
Вы также можете принудительно включить режим гарантированной точности группировки/агрегации с помощью опции accurate_aggregation.
Устанавливает максимальное время выполнения поискового запроса в миллисекундах. Должно быть неотрицательным целым числом. Значение по умолчанию — 0, что означает «не ограничивать». Локальные поисковые запросы будут остановлены, как только истечет указанное время. Обратите внимание, что если вы выполняете поиск, который запрашивает несколько локальных таблиц, этот лимит применяется к каждой таблице отдельно. Имейте в виду, что это может немного увеличить время отклика запроса из-за накладных расходов, вызванных постоянным отслеживанием, не пора ли остановить запрос.
Целое число. Максимальное прогнозируемое время поиска; см. predicted_time_costs.
none позволяет заменять все термины запроса их точными формами, если таблица была построена с включенной опцией index_exact_words. Это полезно для предотвращения стемминга или лемматизации терминов запроса.
0 или 1 разрешает автономное отрицание для запроса. По умолчанию 0. См. также соответствующую глобальную настройку.
- SQL
MySQL [(none)]> select * from tbl where match('-donald');
ERROR 1064 (42000): index t: query error: query is non-computable (single NOT operator)
MySQL [(none)]> select * from t where match('-donald') option not_terms_only_allowed=1;
+---------------------+-----------+
| id | field |
+---------------------+-----------+
| 1658178727135150081 | smth else |
+---------------------+-----------+Выберите из следующих вариантов:
proximity_bm25bm25nonewordcountproximitymatchanyfieldmasksph04exprexport
Для получения более подробной информации о каждом ранкере обратитесь к Ранжирование результатов поиска.
Позволяет указать конкретное целочисленное значение сида для запроса ORDER BY RAND(), например: ... OPTION rand_seed=1234. По умолчанию для каждого запроса автоматически генерируется новое и разное значение сида.
Целое число. Количество повторных попыток для распределенного поиска.
Целое число. Задержка между повторными попытками для распределенного поиска, в миллисекундах.
Строка. Токен прокрутки для постраничного вывода результатов с использованием Подхода к пагинации Scroll.
pq- очередь с приоритетом, установлена по умолчаниюkbuffer- обеспечивает более быструю сортировку для уже предварительно отсортированных данных, например, данных таблицы, отсортированных по id Результирующий набор одинаков в обоих случаях; выбор того или иного варианта может просто улучшить (или ухудшить) производительность.
Ограничивает максимальное количество потоков, используемых для обработки текущего запроса. По умолчанию — без ограничений (запрос может занять все потоки, определенные глобально). Для пакета запросов опция должна быть прикреплена к самому первому запросу в пакете, и затем она применяется при создании рабочей очереди и действует на весь пакет. Эта опция имеет тот же смысл, что и опция max_threads_per_query, но применяется только к текущему запросу или пакету запросов.
Заключенная в кавычки строка, разделенная двоеточиями: имя библиотеки:имя плагина:необязательная строка настроек. Фильтр токенов времени запроса создается для каждого поиска, когда полнотекстовый поиск вызывается каждой задействованной таблицей, позволяя реализовать пользовательский токенизатор, который генерирует токены в соответствии с пользовательскими правилами.
SELECT * FROM index WHERE MATCH ('yes@no') OPTION token_filter='mylib.so:blend:@'
Ограничивает максимальное количество расширенных ключевых слов для одного подстановочного знака, значение по умолчанию 0 означает отсутствие ограничений. Для получения дополнительных сведений обратитесь к expansion_limit.
В редких случаях встроенный анализатор запросов Manticore может ошибаться в понимании запроса и определении того, следует ли использовать индекс docid, вторичные индексы или колоночное сканирование. Чтобы переопределить решения оптимизатора запросов, вы можете использовать следующие подсказки в своем запросе:
/*+ DocidIndex(id) */для принудительного использования индекса docid,/*+ NO_DocidIndex(id) */чтобы указать оптимизатору игнорировать его/*+ SecondaryIndex(<attr_name1>[, <attr_nameN>]) */для принудительного использования вторичного индекса (если доступен),/*+ NO_SecondaryIndex(id) */чтобы указать оптимизатору игнорировать его/*+ ColumnarScan(<attr_name1>[, <attr_nameN>]) */для принудительного использования колоночного сканирования (если атрибут колоночный),/*+ NO_ColumnarScan(id) */чтобы указать оптимизатору игнорировать его
Обратите внимание, что при выполнении полнотекстового запроса с фильтрами оптимизатор запросов выбирает между пересечением результатов полнотекстового дерева с результатами фильтров или использованием стандартного подхода "сначала сопоставление, затем фильтрация". Указание любой подсказки заставит демона использовать путь выполнения, который осуществляет пересечение результатов полнотекстового дерева с результатами фильтров.
Для получения дополнительной информации о том, как работает оптимизатор запросов, обратитесь к странице Стоимостной оптимизатор.
- SQL
SELECT * FROM students where age > 21 /*+ SecondaryIndex(age) */При использовании клиента MySQL/MariaDB убедитесь, что включен флаг --comments, чтобы активировать подсказки в ваших запросах.
- mysql
mysql -P9306 -h0 --comments