#couchbase #n1ql
#couchbase #n1ql
Вопрос:
У меня есть документы json в моем кластере Couchbase, которые выглядят следующим образом
{
"giata_properties": {
"propertyCodes": {
"provider": [
{
"code": [
{
"value": [
{
"name": "Country Code",
"value": "EG"
},
{
"name": "City Code",
"value": "HRG"
},
{
"name": "Hotel Code",
"value": "91U"
}
]
}
],
"providerCode": "gta",
"providerType": "gds"
},
{
"code": [
{
"value": [
{
"value": "071801"
}
]
},
{
"value": [
{
"value": "766344"
}
]
}
],
"providerCode": "restel",
"providerType": "gds"
},
{
"code": [
{
"value": [
{
"value": "HRG03Z"
}
]
},
{
"value": [
{
"value": "HRG04Z"
}
]
}
],
"providerCode": "5VF",
"providerType": "tourOperator"
}
]
}
}
}
Я пытаюсь создать запрос, который извлекает один документ на основе значения giata_properties.propertyCodes.provider.code.value.value
и конкретного providerType
.
Так, например, мой ввод — это 071801
and restel
, я хочу запрос, который принесет мне документ, который я вставил выше (потому что он содержит эти значения).
Я довольно новичок в N1QL, поэтому до сих пор я пробовал (без ввода providerType)
SELECT * FROM giata_properties AS gp
WHERE ANY `field` IN `gp.propertyCodes.provider.code.value` SATISFIES `field.value` = '071801' END;
Это возвращает мне пустой результирующий набор. Вероятно, я делаю все это неправильно.
правка1:
Согласно ответу geraldss, я смог достичь своей цели с помощью 2 разных запросов
1-й (более общий) ~2m50.9903732s
SELECT * FROM giata_properties AS gp WHERE ANY v WITHIN gp SATISFIES v.`value` = '071801' END;
2-й (более конкретный) ~2m31.3660388s
SELECT * FROM giata_properties AS gp WHERE ANY v WITHIN gp.propertyCodes.provider[*].code SATISFIES v.`value` = '071801' END;
В корзине около 550 тыс. документов. В настоящее время нет индексов, кроме основного.
Вопрос, часть 2
Когда я выполняю любой из вышеперечисленных запросов, я очень быстро получаю результат, передаваемый в мою оболочку, затем я провожу оставшееся время запроса, ожидая, пока движок завершит перебор всех документов. Я уверен, что я получу только 1 результат от будущих запросов, поэтому я подумал, что могу использовать LIMIT 1, чтобы движок прекратил поиск по первому результату, я попробовал что-то вроде
SELECT * FROM giata_properties AS gp WHERE ANY v WITHIN gp SATISFIES v.`value` = '071801' END LIMIT 1;
Но это не имело никакого значения, я получаю документ, записанный в мою оболочку, а затем продолжаю ждать, пока запрос не завершится полностью. Как это можно правильно настроить?
правка2:
Я обновился до последней версии enterprise 4.5.1-2844
, у меня есть только основной индекс, созданный в giata_properties
корзине, когда я выполняю запрос вместе с ключевым словом LIMIT 1, он по-прежнему занимает то же время, он не останавливается быстрее.
Я также пытался создать предложенный вами индекс массива, но запрос не использует индекс и продолжает настаивать на использовании #primary
индекса (даже если я использую предложение USE INDEX).
Я попытался удалить SELF из предложенного вами индекса, и на его создание ушло гораздо больше времени, и теперь запрос может использовать этот новый индекс, но я, честно говоря, не уверен, что я здесь делаю.
Итак, 3 вопроса:
1) Почему ОГРАНИЧЕНИЕ 1 с использованием первичного индекса не приводит к остановке запроса при первом результате?
2) В чем разница между индексом, который вы предложили, с SELF и без SELF? Я попытался найти SELF
документацию по ключевым словам, но ничего не смог найти.
Так выглядят оба индекса в веб-интерфейсе
Индекс 1 (ваше первоначальное предложение) — не работает
CREATE INDEX `gp_idx1` ON `giata_properties`((distinct (array (`v`.`value`) for `v` within (array_star((((self.`giata_properties`).`propertyCodes`).`provider`)).`code`) end)))
Индекс 2 (без SELF
)
CREATE INDEX `gp_idx2` ON `giata_properties`((distinct (array (`v`.`value`) for `v` within (array_star(((self.`propertyCodes`).`provider`)).`code`) end)))
3) Каким будет запрос для конкретного giata_properties.propertyCodes.provider.code.value.value
и конкретного providerCode
? Мне удалось сделать оба по отдельности, но мне не удалось их объединить.
Спасибо за вашу помощь, дорогая
Комментарии:
1. Действительно ли ваш документ содержит поле giata_properties?
2. @geraldss Нет, извините. Вот реальный образец документов, которые у меня есть в
giata_properties
корзине pastebin.com/mbXFMPkA3. Хорошо, это объяснило бы любые несоответствия в решении, @pretty.
4. @geraldss Я виноват. Не могли бы вы ответить на мои 3 вопроса выше? Мне действительно нужен запрос (и индекс), который извлекает документ на основе
value
иproviderCode
.5. Можете ли вы опубликовать новый чистый вопрос. Я отвечу.
Ответ №1:
Вот запрос без providerType
.
EXPLAIN SELECT *
FROM giata_properties AS gp
WHERE ANY v WITHIN gp.giata_properties.propertyCodes.provider[*].code SATISFIES v.`value` = '071801' END;
Вы также можете проиндексировать это в Couchbase 4.5.0 и выше.
CREATE INDEX idx1 ON giata_properties( DISTINCT ARRAY v.`value` FOR v WITHIN SELF.giata_properties.propertyCodes.provider[*].code END );
Редактировать, чтобы ответить на вопрос, редактирует
Производительность была рассмотрена в 4.5.x. Вы должны попробовать следующее в Couchbase 4.5.1 и опубликовать время выполнения здесь.
- Тест на 4.5.1.
- Создайте индекс.
- Используйте ОГРАНИЧЕНИЕ. В 4.5.1 ограничение понижается до индекса.
Комментарии:
1. Спасибо geraldss, это работает, и очень приятно, что вам не нужно указывать, на какое
value
поле вы ссылаетесь в N1QL (кстати, это влияет на производительность?). Но не могли бы вы уточнить, как именно я могу указать в N1QL, на какое поле он должен смотреть? Например, я хочу, чтобы мой запрос просматривал толькоgp.propertyCodes.provider.code.value.value
поля, а не все поля с именемvalue
. Также могу ли я сделать индекс, который вы предложили в версии сообщества 4.1.0?2. Индексация массива доступна только в версии 4.5 и выше. Я отредактирую ответ, чтобы он был немного более конкретным.
3. Интересно, имеет ли этот более конкретный запрос лучшую производительность, чем предыдущий, более общий, я скоро проведу тесты. Большое спасибо.
4. Опубликовал несколько тестов и обновил мой вопрос, помощь была бы очень признательна.