

Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.

# Transmite los resultados de las consultas con el protocolo Bolt
<a name="access-graph-opencypher-streaming"></a>

Al ejecutar una consulta de OpenCypher que devuelve una gran cantidad de registros, no es necesario cargar todo el conjunto de resultados en la memoria del cliente de una sola vez. Neptune admite la transmisión de resultados a través del protocolo Bolt, que permite al conductor buscar los registros en lotes y procesarlos de forma incremental a medida que llegan. Esto puede resultar ventajoso si desea procesar los resultados a medida que los devuelve el servidor, pero requiere configurar `FetchSize` y utilizar una iteración diferida para evitar cargar todo el conjunto de resultados en la memoria.

Esto funciona mediante el mecanismo [PULL Bolt v4.0](https://neo4j.com/docs/bolt/current/bolt/message/#messages-pull). En lugar de solicitar todos los registros en un solo mensaje, el conductor envía una solicitud PULL con un tamaño de lote. Por ejemplo, «deme los siguientes 50 registros». Neptune devuelve esa cantidad de registros junto con una bandera que indica si hay más disponibles. A continuación, el conductor solicita el siguiente lote cuando el cliente esté listo, y esto continúa hasta que el conjunto de resultados se haya consumido por completo.

El tamaño del lote se controla mediante el `FetchSize` ajuste de la configuración de la sesión del conductor. En combinación con la iteración lenta (se procesan los registros de uno en uno a medida que se devuelven), esto limita el uso de la memoria del lado del cliente, independientemente del tamaño del conjunto total de resultados.

**importante**  
`FetchSize`controla el flujo de datos entre el servidor y el cliente. No afecta a la forma en que Neptune ejecuta la consulta. Neptune comienza a ejecutar la consulta y a producir resultados tan pronto como recibe el mensaje RUN. Los resultados se almacenan en el servidor hasta que el cliente los solicite con un mensaje PULL. Si el cliente no consume los resultados dentro del tiempo de espera de la consulta configurado, Neptune finaliza la consulta, descarta los resultados almacenados en el búfer y libera los recursos del lado del servidor. No hay un límite de búfer independiente en el lado del servidor; el almacenamiento en búfer continúa hasta que el cliente extraiga los resultados o se agote el tiempo de espera de la consulta.  
La transmisión es más eficaz cuando las consultas no se agregan y pueden producir resultados de forma incremental. Consultas que incluyen `ORDER BY` funciones de agregación (como `count()``collect()`, o`sum()`) o que `DISTINCT` requieren que Neptune calcule el conjunto de resultados completo antes de devolver cualquier registro. En estos casos, `FetchSize` sigue limitando el uso de memoria del lado del cliente por lote, pero el servidor debe guardar todo el conjunto de resultados en la memoria antes de que comience la transmisión.

**nota**  
El punto final HTTPS de OpenCypher proporciona los resultados mediante la codificación de transferencia fragmentada HTTP, que transmite los datos al cliente a medida que se generan. Sin embargo, el cliente no puede controlar el ritmo de entrega. No existe un equivalente `FetchSize` para el punto final HTTPS. Para controlar el consumo de memoria del lado del cliente con conjuntos de resultados grandes, utilice una conexión de controlador Bolt configurada. `FetchSize`

## Configuración FetchSize y procesamiento de los resultados en lotes
<a name="access-graph-opencypher-streaming-usage"></a>

Establezca `FetchSize` la configuración de sesión o del controlador para controlar cuántos registros solicita el conductor de Neptune por mensaje PULL. Tenga en cuenta que esto `FetchSize` controla el driver-to-server flujo, no el procesamiento por lotes a nivel de aplicación. Para procesar los resultados en lotes a nivel de aplicación (por ejemplo, para realizar trabajos intermedios entre grupos de registros), utilice un método auxiliar que acumule los registros del iterador lento del controlador.

Los siguientes ejemplos muestran ambos aspectos: la configuración `FetchSize` en la sesión y el uso de un método auxiliar para agrupar los registros en lotes de nivel de aplicación para su procesamiento.

**Example Java**  

```
static void processBatches(Result result, int size,
        Consumer<List<Record>> handler) {
    var batch = new ArrayList<Record>();
    while (result.hasNext()) {
        batch.add(result.next());
        if (batch.size() >= size) {
            handler.accept(batch);
            batch = new ArrayList<>();
        }
    }
    if (!batch.isEmpty()) handler.accept(batch);
}

// Usage:
try (Session session = driver.session(SessionConfig.builder()
        .withFetchSize(50)
        .withDefaultAccessMode(AccessMode.READ)
        .build())) {

    Result result = session.run("MATCH (m:movie) RETURN m.title AS title");
    processBatches(result, 10, batch -> {
        for (var record : batch) {
            System.out.println(record.get("title").asString());
        }

        // Do other intermediary work here between batch calls
    });
    result.consume();
}
```

**Example Python**  

```
async def batched(result, size):
    batch = []
    async for record in result:
        batch.append(record)
        if len(batch) >= size:
            yield batch
            batch = []
    if batch:
        yield batch

# Usage:
async with driver.session(fetch_size=50) as session:
    result = await session.run("MATCH (m:movie) RETURN m.title AS title")
    async for batch in batched(result, 10):
        for record in batch:
            print(record["title"])

        # Do other intermediary work here between batch calls
```

**Example Go**  

```
func processBatches(ctx context.Context, result neo4j.ResultWithContext,
        size int, handler func([]*neo4j.Record)) error {
    var batch []*neo4j.Record
    for result.Next(ctx) {
        batch = append(batch, result.Record())
        if len(batch) >= size {
            handler(batch)
            batch = nil
        }
    }
    if len(batch) > 0 {
        handler(batch)
    }
    return result.Err()
}

// Usage:
session := driver.NewSession(ctx, neo4j.SessionConfig{
    AccessMode: neo4j.AccessModeRead,
    FetchSize:  50,
})
defer session.Close(ctx)

result, err := session.Run(ctx,
    "MATCH (m:movie) RETURN m.title AS title", nil)
if err != nil {
    log.Fatal(err)
}

if err := processBatches(ctx, result, 10, func(batch []*neo4j.Record) {
    for _, record := range batch {
        title, _ := record.Get("title")
        fmt.Println(title)
    }

    // Do other intermediary work here between batch calls
}); err != nil {
    log.Fatal(err)
}
```

**Example .NET**  

```
static async IAsyncEnumerable<List<IRecord>> Batched(
        IResultCursor result, int size)
{
    var batch = new List<IRecord>();
    while (await result.FetchAsync())
    {
        batch.Add(result.Current);
        if (batch.Count >= size)
        {
            yield return batch;
            batch = new List<IRecord>();
        }
    }
    if (batch.Count > 0) yield return batch;
}

// Usage:
await using var session = driver.AsyncSession(o => o
    .WithFetchSize(50)
    .WithDefaultAccessMode(AccessMode.Read));

var result = await session.RunAsync("MATCH (m:movie) RETURN m.title AS title");
await foreach (var batch in Batched(result, 10))
{
    foreach (var record in batch)
    {
        Console.WriteLine(record["title"].As<string>());
    }

    // Do other intermediary work here between batch calls
}
```

**Example Node.js**  

```
// Uses for-await-of on the Result's async iterator (Neo4j driver v5+).
// This is pull-based: the driver pauses fetching while the loop body
// executes, providing natural backpressure. This is preferred over
// result.subscribe(), which is push-based and continues delivering
// records during async processing.
async function* batched(result, size) {
    let batch = [];
    for await (const record of result) {
        batch.push(record);
        if (batch.length >= size) {
            yield batch;
            batch = [];
        }
    }
    if (batch.length > 0) yield batch;
}

// Usage:
const session = driver.session({
    defaultAccessMode: neo4j.session.READ,
    fetchSize: 50
});

try {
    const result = session.run('MATCH (m:movie) RETURN m.title AS title');
    for await (const batch of batched(result, 10)) {
        for (const record of batch) {
            console.log(record.get('title'));
        }

        // Do other intermediary work here between batch calls
    }
} finally {
    await session.close();
}
```

## Consumo entusiasta frente a consumo incremental
<a name="access-graph-opencypher-streaming-avoid"></a>

Los siguientes métodos se bloquean hasta que todo el conjunto de resultados se recopila en la memoria, lo que impide que la aplicación actúe en función de los resultados a medida que llegan:
+ **Java:** `result.list()`
+ **Python:**`result.data()`, `list(result)`
+ **Ve:**`result.Collect(ctx)`, `neo4j.EagerResultTransformer`
+ **.NET:** `result.ToListAsync()`
+ **Node.js:** `const { records } = await result`

Para procesar los resultados de forma incremental, utilice los patrones de iteración diferida y de ayuda por lotes que se muestran en los ejemplos anteriores.