

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 使用 Gremlin 流式传输查询结果
<a name="access-graph-gremlin-streaming"></a>

当您运行返回大量结果的 Gremlin 遍历时，Neptune 会通过连接将它们分批传输回客户端。 WebSocket Neptune 在生成结果批次时发送结果批次，无需等待客户端请求更多。如果您想在服务器返回结果时对其进行处理，这可能非常有利，但需要使用延迟迭代模式以避免将完整的结果集收集到内存中。

默认情况下，海王星分批发送结果，每 WebSocket 帧 64 个。您无法更改此服务器端默认值，但是可以使用请求选项（在 Java 驱动程序中调用，或`connectionPool.resultIterationBatchSize`作为驱动程序级别的默认值），根据来自客户端`Tokens.ARGS_BATCH_SIZE`的每个[`batchSize`](https://tinkerpop.apache.org/docs/current/reference/#gremlin-java-configuration)请求来覆盖批处理大小。

有关使用其他语言驱动程序进行配置`batchSize`的详细信息，请参阅 [ Apache TinkerPop Gremlin 驱动程序和变体](https://tinkerpop.apache.org/docs/current/reference/#gremlin-drivers-variants)文档中每个驱动程序的配置部分。

由于服务器会自动推送结果，因此客户端的背压是通过 TCP 和流量控制隐式处理的。 WebSocket 如果客户端从套接字读取的速度很慢，服务器的写入操作最终将阻塞，直到客户端赶上。

**重要**  
通过遍历可以逐步产生结果，流式传输最为有效。包含`order()`、、`groupCount()``group()``dedup()`、或其他需要在发出结果之前完成完整遍历的步骤的遍历将导致 Neptune 在开始流式传输之前在内存中实现整个结果集。在这些情况下，批处理仍然可以减少每帧的序列化开销，但不会减少服务器端的内存使用量。

## 逐步消耗结果
<a name="access-graph-gremlin-streaming-usage"></a>

要在结果到达时对其进行处理，请使用`hasNext()`/`next()`或等效的 API 进行延迟迭代，而不是将所有结果收集到列表中。您可以使用`next(batchSize)`在应用程序级批次中提取结果，从而允许您在服务器继续生成结果的同时，在批次之间执行中间工作。

**Example Java（GLV 字节码）**  

```
GraphTraversalSource g = traversal().withRemote(connection);

int batchSize = 10;
int batchNum = 0;
var traversal = g.V().hasLabel("movie").values("title").limit(1000);
while (traversal.hasNext()) {
    var batch = traversal.next(batchSize);
    batchNum++;
    for (var title : batch) {
        System.out.println("  " + title);
    }

    // Do other intermediary work here between batch calls
    System.out.println("Batch " + batchNum + " processing complete\n");
}
```

**Example Python**  

```
g = traversal().with_remote(connection)

BATCH_SIZE = 10
batch_num = 0
t = g.V().has_label('movie').values('title').limit(1000)
while t.has_next():
    batch = t.next(BATCH_SIZE)
    batch_num += 1
    for title in batch:
        print(f"  {title}")

    # Do other intermediary work here between batch calls
    print(f"Batch {batch_num} processing complete\n")
```

**Example Go**  

```
// The Go driver does not support next(n), so batches are accumulated manually.
g := gremlingo.Traversal_().WithRemote(connection)

resultSet, err := g.V().HasLabel("movie").Values("title").Limit(1000).GetResultSet()
if err != nil {
    log.Fatal(err)
}

batchSize := 10
batchNum := 0
for {
    var batch []interface{}
    for i := 0; i < batchSize; i++ {
        result, ok, err := resultSet.One() // returns (value, ok, error); ok is false when results are exhausted
        if err != nil {
            log.Fatal(err)
        }
        if !ok {
            break
        }
        batch = append(batch, result)
    }
    if len(batch) == 0 {
        break
    }
    batchNum++
    for _, v := range batch {
        fmt.Printf("  %v\n", v)
    }

    // Do other intermediary work here between batch calls
    fmt.Printf("Batch %d processing complete\n\n", batchNum)
}
```

**Example .NET**  

```
var g = Traversal().WithRemote(connection);

var batchSize = 10;
var batchNum = 0;
var traversal = g.V().HasLabel("movie").Values<string>("title").Limit<string>(1000);
while (traversal.HasNext())
{
    var batch = traversal.Next(batchSize);
    batchNum++;
    foreach (var title in batch)
    {
        Console.WriteLine($"  {title}");
    }

    // Do other intermediary work here between batch calls
    Console.WriteLine($"Batch {batchNum} processing complete\n");
}
```

**Example Node.js**  

```
// The Node.js driver does not support next(n), so batches are accumulated manually.
const g = traversal().withRemote(connection);

const batchSize = 10;
let batchNum = 0;
const t = g.V().hasLabel('movie').values('title').limit(1000);
while (true) {
    const batch = [];
    for (let i = 0; i < batchSize; i++) {
        const result = await t.next();
        if (result.done) break;
        batch.push(result.value);
    }
    if (batch.length === 0) break;
    batchNum++;
    for (const title of batch) {
        console.log(`  ${title}`);
    }

    // Do other intermediary work here between batch calls
    console.log(`Batch ${batchNum} processing complete\n`);
}
```

## 急切消费与增量消费
<a name="access-graph-gremlin-streaming-avoid"></a>

流式传输允许您在获取和返回更多数据时逐步处理结果。在将整个结果集收集到内存中之前，以下方法会阻塞，从而防止您的应用程序在结果到达时对结果采取行动：
+ **Java：**`toList()`或 `toSet()`
+ **Python：**`toList()`或 `toSet()`
+ **去:**`ToList()`、`ToSet()`、或 `GetResultSet().GetAll()`
+ **.NET：**`ToList()`或 `Promise()`
+ **Node.js:** `toList()`

**注意**  
即使使用这些方法，数据仍会以增量方式通过 WebSocket 连接流动。区别在于，在整个收集完成之前，您的应用程序无法处理单个结果。要在结果到达时对其进行处理，请使用上面示例中显示的延迟迭代或批处理模式。