Google BigQuery es el almacén de datos sin servidor de Google, construido para ejecutar consultas analíticas sobre tablas muy grandes. Cuando quieres sacar datos de tablas de BigQuery hacia tu propia aplicación, el camino más rápido es la API BigQuery Storage Read, un servicio gRPC que transmite filas directamente desde el almacenamiento en lugar de paginarlas a través de un endpoint REST. sgcWebSockets Enterprise incluye un cliente gRPC de BigQuery tipado que se apoya sobre TsgcGRPCClient, así que puedes leer una tabla de BigQuery desde Delphi y C++Builder sin ningún runtime gRPC externo.
Cómo funciona
La API Storage Read es un servicio gRPC llamado google.cloud.bigquery.storage.v1.BigQueryRead. gRPC son Protocol Buffers enmarcados sobre HTTP/2, así que el cliente se ejecuta sobre la pila HTTP/2 de sgcWebSockets. Apuntas un TsgcHTTP2Client a bigquerystorage.googleapis.com en el puerto 443 con TLS, lo asignas a un TsgcGRPCClient, y el cliente gRPC gestiona el enmarcado de mensajes, las cabeceras, los timeouts y los trailers por ti.
Leer una tabla es un patrón de dos llamadas. Primero llamas a CreateReadSession, una llamada unaria que pide a BigQuery que abra una sesión sobre una tabla y devuelva uno o más streams de lectura. Luego llamas a ReadRows en un stream, una llamada con streaming desde el servidor: envías una petición y el servidor empuja de vuelta una secuencia de lotes de filas hasta que el stream termina. Los mensajes tipados de BigQuery en sgcGRPC_Google_BigQuery construyen los protobufs de las peticiones y analizan las respuestas, así que trabajas con clases Delphi en lugar de bytes ensamblados a mano.
Autenticación
BigQuery se autentica con una cuenta de servicio de Google Cloud. La demo carga el JSON de la cuenta de servicio, construye un JWT autofirmado y lo intercambia por un token de acceso, luego envía ese token como metadata gRPC en cada llamada. Como un JWT de cuenta de servicio autofirmado está vinculado a la audiencia, el token tiene que apuntar al endpoint de BigQuery Storage para que sea aceptado por bigquerystorage.googleapis.com.
GoogleCloud.GoogleCloudOptions.Authentication := gcaJWT;
GoogleCloud.GoogleCloudOptions.JWT.ClientEmail := ClientEmail;
GoogleCloud.GoogleCloudOptions.JWT.PrivateKeyId := PrivateKeyId;
GoogleCloud.GoogleCloudOptions.JWT.PrivateKey.Text := PrivateKey;
GoogleCloud.GoogleCloudOptions.JWT.ProjectId := ProjectId;
GoogleCloud.GoogleCloudOptions.JWT.API_Endpoint :=
'https://bigquerystorage.googleapis.com/';
// once the token is acquired, attach it to every gRPC call
GRPC.DefaultMetadata.Add('authorization', 'Bearer ' + Token);
Configurar el cliente
Un canal gRPC es una conexión HTTP/2. Crea el transporte, apúntalo al host de BigQuery Storage, luego crea el cliente gRPC y asigna el transporte a su propiedad Client. El content type es el formato de cable binario proto y la compresión se deja desactivada.
uses
sgcHTTP2_Client, sgcGRPC_Client, sgcGRPC_Types, sgcGRPC_Google_BigQuery;
var
HTTP2: TsgcHTTP2Client;
GRPC: TsgcGRPCClient;
begin
HTTP2 := TsgcHTTP2Client.Create(nil);
HTTP2.Host := 'bigquerystorage.googleapis.com';
HTTP2.Port := 443;
HTTP2.TLS := True;
GRPC := TsgcGRPCClient.Create(nil);
GRPC.Client := HTTP2;
GRPC.ChannelOptions.ContentType := grpcProto;
GRPC.ChannelOptions.Compression := grpcNoCompression;
HTTP2.Active := True;
end;
Crear una sesión de lectura
Para abrir una sesión rellenas un TsgcGRPCBigQueryCreateReadSessionRequest. El Parent es tu proyecto de facturación, el ReadSession.Table es la ruta completa de la tabla, y DataFormat selecciona el formato de cable de las filas (1 = Avro, 2 = Arrow). MaxStreamCount limita cuántos streams de lectura paralelos devuelve BigQuery. Serializa la petición con ToBytes y envíala como un Call unario; la respuesta es un ReadSession que cargas con LoadFromBytes para leer de vuelta los nombres de los streams.
var
oRequest: TsgcGRPCBigQueryCreateReadSessionRequest;
oResponse: TsgcGRPCResponse;
oSession: TsgcGRPCBigQueryReadSession;
begin
oRequest := TsgcGRPCBigQueryCreateReadSessionRequest.Create;
try
oRequest.Parent := 'projects/' + ProjectId;
oRequest.ReadSession.Table := 'projects/' + ProjectId +
'/datasets/' + Dataset + '/tables/' + Table;
oRequest.ReadSession.DataFormat := 1; { AVRO }
oRequest.MaxStreamCount := 1;
oResponse := GRPC.Call(
'google.cloud.bigquery.storage.v1.BigQueryRead',
'CreateReadSession', oRequest.ToBytes);
if oResponse.StatusCode = grpcOK then
begin
oSession := TsgcGRPCBigQueryReadSession.Create;
try
oSession.LoadFromBytes(oResponse.Data);
// keep the first read stream name for ReadRows
if oSession.StreamCount > 0 then
FReadStreamName := oSession.Stream(0).Name;
finally
oSession.Free;
end;
end;
finally
oRequest.Free;
end;
end;
Transmitir las filas
Con un nombre de stream en mano llamas a ReadRows. Establece ReadStream al nombre del stream y un Offset de inicio opcional, luego envíalo con CallAsync para una respuesta con streaming desde el servidor. Cada lote que el servidor empuja lanza OnGRPCStreamMessage, y OnGRPCStreamEnd se dispara una vez cuando el stream ha terminado.
var
oRequest: TsgcGRPCBigQueryReadRowsRequest;
begin
oRequest := TsgcGRPCBigQueryReadRowsRequest.Create;
try
oRequest.ReadStream := FReadStreamName;
oRequest.Offset := 0;
GRPC.CallAsync('google.cloud.bigquery.storage.v1.BigQueryRead',
'ReadRows', oRequest.ToBytes);
finally
oRequest.Free;
end;
end;
procedure TForm1.OnGRPCStreamMessage(Sender: TObject;
const aMessage: TsgcGRPCStreamMessage; var aCancel: Boolean);
var
oResponse: TsgcGRPCBigQueryReadRowsResponse;
begin
oResponse := TsgcGRPCBigQueryReadRowsResponse.Create;
try
oResponse.LoadFromBytes(aMessage.Data);
if oResponse.AvroRows.RowCount > 0 then
// oResponse.AvroRows.SerializedBinaryRows holds the Avro block
else if oResponse.ArrowRecordBatch.RowCount > 0 then
// oResponse.ArrowRecordBatch.SerializedRecordBatch holds the Arrow batch
finally
oResponse.Free;
end;
end;
Formatos de fila Avro y Arrow
BigQuery no devuelve las filas como campos analizados por el cable. Devuelve bloques serializados en uno de dos formatos columnares, y eliges el formato cuando creas la sesión. Con DataFormat := 1 la respuesta lleva AvroRows, cuyo campo SerializedBinaryRows contiene un bloque codificado en Avro y RowCount te dice cuántas filas contiene. Con DataFormat := 2 la respuesta lleva un ArrowRecordBatch, cuyo campo SerializedRecordBatch contiene un record batch de Apache Arrow. Decodificas el bloque con tu librería de Avro o Arrow preferida. El esquema de la sesión, devuelto junto con los streams, describe los nombres y tipos de las columnas para que sepas qué contiene cada bloque.
Filtrar y proyectar
No tienes que leer filas enteras. La sesión de lectura lleva un objeto ReadOptions que te permite empujar una proyección y un filtro hacia BigQuery para que envíe menos datos. Añade nombres de columna a SelectedFields para proyectar solo las columnas que necesitas, y establece RowRestriction a un predicado de estilo SQL para filtrar filas del lado del servidor antes de que se transmitan.
oRequest.ReadSession.ReadOptions.SelectedFields.Add('name');
oRequest.ReadSession.ReadOptions.SelectedFields.Add('state');
oRequest.ReadSession.ReadOptions.RowRestriction := 'state = "CA"';
Disponibilidad
El cliente gRPC de BigQuery forma parte de la edición Enterprise de sgcWebSockets y se ejecuta en Windows, macOS, Linux, iOS y Android. Un ejemplo listo para ejecutar, con el cargador de la cuenta de servicio y el flujo de crear sesión y leer filas mostrado arriba, está en Demos\21.GRPC\16.BigQuery. La referencia completa, incluidos los demás clientes gRPC de Google Cloud, está en la página de producto del Cliente gRPC.
¿Preguntas o comentarios? Ponte en contacto. Recibirás respuesta de las personas que escribieron el código.
