N1QL вложенный json, запрос к полю внутри объекта внутри массива

#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/mbXFMPkA

3. Хорошо, это объяснило бы любые несоответствия в решении, @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. Опубликовал несколько тестов и обновил мой вопрос, помощь была бы очень признательна.