BigQuery NodeJS SDK не создает собственный тип ГЕОГРАФИИ

#node.js #google-bigquery

#node.js #google-bigquery

Вопрос:

Во-первых, простой BigQuery SQL:

Мы пытаемся взять следующий выполняемый SQL-запрос BigQuery и преобразовать его в параметризованный запрос для выполнения в Node.js:

 SELECT * FROM UNNEST([
  STRUCT(
    ST_GEOGFROMTEXT('POINT(1 2)') AS lnglat, 
    TIMESTAMP('2020-01-01') AS stamp
  )
])
  

Запрос просто создает псевдотаблицу из массива структур. В частности, типы выходных данных соответствуют ожидаемым, столбец stamp является TIMESTAMP типом BigQuery и lnglat является GEOGRAPHY типом BigQuery.

Теперь давайте попробуем Node.js .

Давайте заменим массив структур BigQuery выше на @points , и передадим массив объектных литералов JavaScript как params :

 
// this is version 5.3.0
const { BigQuery, Geography } = require('@google-cloud/bigquery');

const bigquery = new BigQuery();

(async () => {

  const query = 'SELECT * from UNNEST(@points)';

  const params =  { points: [
    {
      lnglat: new Geography('POINT(1 2)'),
      stamp: BigQuery.timestamp('2020-01-01')
    }
  ] };

  const [job] = await bigquery.createQueryJob({ query, params });

  // Wait for the query to finish
  const [rows] = await job.getQueryResults();

  // Print the results
  console.log('Rows:');
  console.log(rows);

})();

  

Возвращает следующий результат в моем CLI:

 > node index.js
Rows:
[
  {
    lnglat: { value: 'POINT(1 2)' },
    stamp: BigQueryTimestamp { value: '2020-01-01T00:00:00.000Z' }
  }
]
  

Проблема в том, что, несмотря на NodeJS SDK, содержащий документы по «Географии» здесь, здесь и здесь, ни один из этих методов, похоже, фактически не заставляет BigQuery создавать собственный GEOGRAPHY тип BigQuery внутри BigQuery.

Похоже, вместо этого BigQuery интерпретирует new Geography() как RECORD тип с value полем, указанным в ответе выше, а также проверяется путем проверки временной (анонимной) таблицы, созданной в пользовательском интерфейсе BigQuery:

Схема пользовательского интерфейса BigQuery

Мы пробовали разные варианты функций / классов географии: Geography , BigQuery.Geography , и bigquery.Geography ; все они возвращают один и тот же RECORD тип.


Как ни странно, если вместо этого мы запрашиваем существующую таблицу (в отличие от построения псевдотаблицы во время выполнения), результат будет более соответствовать тому, что я ожидал:

 Rows:
[ { lnglat: Geography { value: 'POINT(-118.43356046 45.97057312)' } } ]
  

Обратите внимание на Geography тип в ответе!


Мы знаем, что мы можем отказаться от указания lnglat в качестве строкового литерала JavaScript, и следующий SQL преобразует его в собственную ГЕОГРАФИЮ, обернув в CTE:

 WITH points AS (
  SELECT * from UNNEST(@points)
) 
SELECT * EXCEPT(lnglat), ST_GEOGFROMTEXT(lnglat) AS lnglat FROM points
  

Но, к сожалению, мы хотим использовать эту псевдотаблицу в качестве фильтра для гораздо большей таблицы на диске, а использование этой CTE-оболочки исключает возможность для этого запроса (не проиллюстрированного здесь) использовать кластеризацию. Кластеризация очень важна для экономии средств и производительности выполнения. Я могу подробнее рассказать об этом, если вы попросите.

В конце концов, это все еще не объясняет, почему собственные географии не материализуются в псевдотаблице.

Вопрос:

Как мы можем использовать BigQuery NodeJS SDK для создания собственного GEOGRAPHY типа BigQuery, аналогичного тому, что мы можем сделать с BigQuery.timestamp() (выше), без CTE?

Комментарии:

1. Это ошибка в библиотеке. Я открыл исправление: github.com/googleapis/nodejs-bigquery/pull/877

2. приятно видеть, что это исправлено! спасибо @SteffanyBrown