Bolt プロトコルを使用した Neptune への openCypher クエリの実行 - Amazon Neptune

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

Bolt プロトコルを使用した Neptune への openCypher クエリの実行

Bolt は、当初 Neo4j によって開発され、クリエイティブコモンズ 3.0 アトリビューションライセンスShareAlikeに基づいてライセンスされたステートメント指向のクライアント/サーバープロトコルです。これは、クライアント駆動型です。つまり、クライアントは常にメッセージ交換を開始します。

Neo4j の Bolt ドライバーを使用して Neptune に接続するには、 boltURIスキームを使用して URLおよび ポート番号をクラスターエンドポイントに置き換えるだけです。1 つの Neptune インスタンスが実行されている場合は、read_write エンドポイントを使用します。複数のインスタンスが実行されている場合は、ライター用とすべてのリードレプリカ用に 2 つのドライバを推奨します。デフォルトの 2 つのエンドポイントしかない場合は、read_write と read_only ドライバで十分ですが、カスタムエンドポイントがある場合は、それぞれにドライバインスタンスを作成することを検討してください。

注記

Bolt 仕様では、Bolt は TCPまたは のいずれかを使用して接続できると記載されていますが WebSockets、Neptune は Bolt TCPの接続のみをサポートします。

Neptune では、最大 1000 の Bolt の同時接続が可能です。

Bolt ドライバーを使用するさまざまな言語の openCypher クエリの例については、Neo4j ドライバーと言語ガイドのドキュメントを参照してください。

重要

Python、.、および Golang 用の Neo4j Bolt ドライバーはNET JavaScript、当初、 の自動更新をサポートしていませんでした。 AWS 署名 v4 認証トークン。つまり、署名の有効期限が切れると (多くの場合 5 分後)、ドライバーは認証に失敗し、それ以降のリクエストも失敗しました。以下の Python、.NET JavaScript、Go の例はすべて、この問題の影響を受けました。

詳細については、Neo4j Python ドライバーの問題 #834Neo4j 。NET の問題 #664Neo4j JavaScript ドライバーの問題 #993Neo4j goLang ドライバーの問題 #429」を参照してください。

ドライバーバージョン 5.8.0 以降、Go ドライバーの新しいプレビュー再認証がリリースAPIされました (「v5.8.0 - フィードバックが再認証に必要になりました」を参照)。

Bolt と Java を使用して Neptune に接続するには

Maven MVNリポジトリ から使用する任意のバージョンのドライバーをダウンロードすることも、プロジェクトにこの依存関係を追加することもできます。

<dependency> <groupId>org.neo4j.driver</groupId> <artifactId>neo4j-java-driver</artifactId> <version>4.3.3</version> </dependency>

次に、これらの Bolt ドライバの 1 つを使用して Java で Neptune に接続するには、次のようなコードを使用して、クラスター内のプライマリ/ライターインスタンスのドライバインスタンスを作成します。

import org.neo4j.driver.Driver; import org.neo4j.driver.GraphDatabase; final Driver driver = GraphDatabase.driver("bolt://(your cluster endpoint URL):(your cluster port)", AuthTokens.none(), Config.builder().withEncryption() .withTrustStrategy(TrustStrategy.trustSystemCertificates()) .build());

1 つ以上のリーダーレプリカがある場合は、同様に、次のようなコードを使用して、それらのドライバインスタンスを作成できます。

final Driver read_only_driver = // (without connection timeout) GraphDatabase.driver("bolt://(your cluster endpoint URL):(your cluster port)", Config.builder().withEncryption() .withTrustStrategy(TrustStrategy.trustSystemCertificates()) .build());

または、タイムアウトを設定して:

final Driver read_only_timeout_driver = // (with connection timeout) GraphDatabase.driver("bolt://(your cluster endpoint URL):(your cluster port)", Config.builder().withConnectionTimeout(30, TimeUnit.SECONDS) .withEncryption() .withTrustStrategy(TrustStrategy.trustSystemCertificates()) .build());

カスタムエンドポイントがある場合は、各エンドポイントにドライバインスタンスを作成することをお勧めします。

Bolt を使用した Python openCypher クエリの例

Bolt を使用して Python で openCypher クエリを作成する方法は次のとおりです。

python -m pip install neo4j
from neo4j import GraphDatabase uri = "bolt://(your cluster endpoint URL):(your cluster port)" driver = GraphDatabase.driver(uri, auth=("username", "password"), encrypted=True)

auth パラメータは無視される点に注意してください。

Bolt を使用した .NET openCypher query の例

Bolt を使用して で openCypher クエリを実行する最初のステップは、 NETを使用して Neo4j ドライバーをインストールすることです NuHet。同期呼び出しを行うには、次のように .Simple バージョンを使用します。

Install-Package Neo4j.Driver.Simple-4.3.0
using Neo4j.Driver; namespace hello { // This example creates a node and reads a node in a Neptune // Cluster where IAM Authentication is not enabled. public class HelloWorldExample : IDisposable { private bool _disposed = false; private readonly IDriver _driver; private static string url = "bolt://(your cluster endpoint URL):(your cluster port)"; private static string createNodeQuery = "CREATE (a:Greeting) SET a.message = 'HelloWorldExample'"; private static string readNodeQuery = "MATCH(n:Greeting) RETURN n.message"; ~HelloWorldExample() => Dispose(false); public HelloWorldExample(string uri) { _driver = GraphDatabase.Driver(uri, AuthTokens.None, o => o.WithEncryptionLevel(EncryptionLevel.Encrypted)); } public void createNode() { // Open a session using (var session = _driver.Session()) { // Run the query in a write transaction var greeting = session.WriteTransaction(tx => { var result = tx.Run(createNodeQuery); // Consume the result return result.Consume(); }); // The output will look like this: // ResultSummary{Query=`CREATE (a:Greeting) SET a.message = 'HelloWorldExample"..... Console.WriteLine(greeting); } } public void retrieveNode() { // Open a session using (var session = _driver.Session()) { // Run the query in a read transaction var greeting = session.ReadTransaction(tx => { var result = tx.Run(readNodeQuery); // Consume the result. Read the single node // created in a previous step. return result.Single()[0].As<string>(); }); // The output will look like this: // HelloWorldExample Console.WriteLine(greeting); } } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (_disposed) return; if (disposing) { _driver?.Dispose(); } _disposed = true; } public static void Main() { using (var apiCaller = new HelloWorldExample(url)) { apiCaller.createNode(); apiCaller.retrieveNode(); } } } }

Bolt とIAM認証を使用した Java openCypher クエリの例

以下の Java コードは、IAM認証で Bolt を使用して Java で openCypher クエリを実行する方法を示しています。 JavaDoc コメントにはその使用法が説明されています。ドライバーインスタンスが使用可能になると、そのインスタンスを使用して複数の認証リクエストを行うことができます。

package software.amazon.neptune.bolt; import com.amazonaws.DefaultRequest; import com.amazonaws.Request; import com.amazonaws.auth.AWS4Signer; import com.amazonaws.auth.AWSCredentialsProvider; import com.amazonaws.http.HttpMethodName; import com.google.gson.Gson; import lombok.Builder; import lombok.Getter; import lombok.NonNull; import org.neo4j.driver.Value; import org.neo4j.driver.Values; import org.neo4j.driver.internal.security.InternalAuthToken; import org.neo4j.driver.internal.value.StringValue; import java.net.URI; import java.util.Collections; import java.util.HashMap; import java.util.Map; import static com.amazonaws.auth.internal.SignerConstants.AUTHORIZATION; import static com.amazonaws.auth.internal.SignerConstants.HOST; import static com.amazonaws.auth.internal.SignerConstants.X_AMZ_DATE; import static com.amazonaws.auth.internal.SignerConstants.X_AMZ_SECURITY_TOKEN; /** * Use this class instead of `AuthTokens.basic` when working with an IAM * auth-enabled server. It works the same as `AuthTokens.basic` when using * static credentials, and avoids making requests with an expired signature * when using temporary credentials. Internally, it generates a new signature * on every invocation (this may change in a future implementation). * * Note that authentication happens only the first time for a pooled connection. * * Typical usage: * * NeptuneAuthToken authToken = NeptuneAuthToken.builder() * .credentialsProvider(credentialsProvider) * .region("aws region") * .url("cluster endpoint url") * .build(); * * Driver driver = GraphDatabase.driver( * authToken.getUrl(), * authToken, * config * ); */ public class NeptuneAuthToken extends InternalAuthToken { private static final String SCHEME = "basic"; private static final String REALM = "realm"; private static final String SERVICE_NAME = "neptune-db"; private static final String HTTP_METHOD_HDR = "HttpMethod"; private static final String DUMMY_USERNAME = "username"; @NonNull private final String region; @NonNull @Getter private final String url; @NonNull private final AWSCredentialsProvider credentialsProvider; private final Gson gson = new Gson(); @Builder private NeptuneAuthToken( @NonNull final String region, @NonNull final String url, @NonNull final AWSCredentialsProvider credentialsProvider ) { // The superclass caches the result of toMap(), which we don't want super(Collections.emptyMap()); this.region = region; this.url = url; this.credentialsProvider = credentialsProvider; } @Override public Map<String, Value> toMap() { final Map<String, Value> map = new HashMap<>(); map.put(SCHEME_KEY, Values.value(SCHEME)); map.put(PRINCIPAL_KEY, Values.value(DUMMY_USERNAME)); map.put(CREDENTIALS_KEY, new StringValue(getSignedHeader())); map.put(REALM_KEY, Values.value(REALM)); return map; } private String getSignedHeader() { final Request<Void> request = new DefaultRequest<>(SERVICE_NAME); request.setHttpMethod(HttpMethodName.GET); request.setEndpoint(URI.create(url)); // Comment out the following line if you're using an engine version older than 1.2.0.0 request.setResourcePath("/opencypher"); final AWS4Signer signer = new AWS4Signer(); signer.setRegionName(region); signer.setServiceName(request.getServiceName()); signer.sign(request, credentialsProvider.getCredentials()); return getAuthInfoJson(request); } private String getAuthInfoJson(final Request<Void> request) { final Map<String, Object> obj = new HashMap<>(); obj.put(AUTHORIZATION, request.getHeaders().get(AUTHORIZATION)); obj.put(HTTP_METHOD_HDR, request.getHttpMethod()); obj.put(X_AMZ_DATE, request.getHeaders().get(X_AMZ_DATE)); obj.put(HOST, request.getHeaders().get(HOST)); obj.put(X_AMZ_SECURITY_TOKEN, request.getHeaders().get(X_AMZ_SECURITY_TOKEN)); return gson.toJson(obj); } }

Bolt とIAM認証を使用した Python openCypher クエリの例

以下の Python クラスでは、IAM認証で Bolt を使用して Python で openCypher クエリを実行できます。

import json from neo4j import Auth from botocore.awsrequest import AWSRequest from botocore.credentials import Credentials from botocore.auth import ( SigV4Auth, _host_from_url, ) SCHEME = "basic" REALM = "realm" SERVICE_NAME = "neptune-db" DUMMY_USERNAME = "username" HTTP_METHOD_HDR = "HttpMethod" HTTP_METHOD = "GET" AUTHORIZATION = "Authorization" X_AMZ_DATE = "X-Amz-Date" X_AMZ_SECURITY_TOKEN = "X-Amz-Security-Token" HOST = "Host" class NeptuneAuthToken(Auth): def __init__( self, credentials: Credentials, region: str, url: str, **parameters ): # Do NOT add "/opencypher" in the line below if you're using an engine version older than 1.2.0.0 request = AWSRequest(method=HTTP_METHOD, url=url + "/opencypher") request.headers.add_header("Host", _host_from_url(request.url)) sigv4 = SigV4Auth(credentials, SERVICE_NAME, region) sigv4.add_auth(request) auth_obj = { hdr: request.headers[hdr] for hdr in [AUTHORIZATION, X_AMZ_DATE, X_AMZ_SECURITY_TOKEN, HOST] } auth_obj[HTTP_METHOD_HDR] = request.method creds: str = json.dumps(auth_obj) super().__init__(SCHEME, DUMMY_USERNAME, creds, REALM, **parameters)

このクラスを使用してドライバーを次のように作成します。

authToken = NeptuneAuthToken(creds, REGION, URL) driver = GraphDatabase.driver(URL, auth=authToken, encrypted=True)

IAM 認証と Bolt を使用した Node.js の例

以下の Node.js コードは、 を使用します。 AWS SDK リクエストを認証するドライバーを作成するための JavaScript バージョン 3 および のES6構文:

import neo4j from "neo4j-driver"; import { HttpRequest } from "@aws-sdk/protocol-http"; import { defaultProvider } from "@aws-sdk/credential-provider-node"; import { SignatureV4 } from "@aws-sdk/signature-v4"; import crypto from "@aws-crypto/sha256-js"; const { Sha256 } = crypto; import assert from "node:assert"; const region = "us-west-2"; const serviceName = "neptune-db"; const host = "(your cluster endpoint URL)"; const port = 8182; const protocol = "bolt"; const hostPort = host + ":" + port; const url = protocol + "://" + hostPort; const createQuery = "CREATE (n:Greeting {message: 'Hello'}) RETURN ID(n)"; const readQuery = "MATCH(n:Greeting) WHERE ID(n) = $id RETURN n.message"; async function signedHeader() { const req = new HttpRequest({ method: "GET", protocol: protocol, hostname: host, port: port, // Comment out the following line if you're using an engine version older than 1.2.0.0 path: "/opencypher", headers: { host: hostPort } }); const signer = new SignatureV4({ credentials: defaultProvider(), region: region, service: serviceName, sha256: Sha256 }); return signer.sign(req, { unsignableHeaders: new Set(["x-amz-content-sha256"]) }) .then((signedRequest) => { const authInfo = { "Authorization": signedRequest.headers["authorization"], "HttpMethod": signedRequest.method, "X-Amz-Date": signedRequest.headers["x-amz-date"], "Host": signedRequest.headers["host"], "X-Amz-Security-Token": signedRequest.headers["x-amz-security-token"] }; return JSON.stringify(authInfo); }); } async function createDriver() { let authToken = { scheme: "basic", realm: "realm", principal: "username", credentials: await signedHeader() }; return neo4j.driver(url, authToken, { encrypted: "ENCRYPTION_ON", trust: "TRUST_SYSTEM_CA_SIGNED_CERTIFICATES", maxConnectionPoolSize: 1, // logging: neo4j.logging.console("debug") } ); } function unmanagedTxn(driver) { const session = driver.session(); const tx = session.beginTransaction(); tx.run(createQuery) .then((res) => { const id = res.records[0].get(0); return tx.run(readQuery, { id: id }); }) .then((res) => { // All good, the transaction will be committed const msg = res.records[0].get("n.message"); assert.equal(msg, "Hello"); }) .catch(err => { // The transaction will be rolled back, now handle the error. console.log(err); }) .then(() => session.close()); } createDriver() .then((driver) => { unmanagedTxn(driver); driver.close(); }) .catch((err) => { console.log(err); });

Bolt とIAM認証を使用した .NET openCypher query の例

でIAM認証を有効にするにはNET、接続を確立するときにリクエストに署名する必要があります。以下の例は、認証トークンを生成する NeptuneAuthToken ヘルパーを作成する方法を示しています。

using Amazon.Runtime; using Amazon.Util; using Neo4j.Driver; using System.Security.Cryptography; using System.Text; using System.Text.Json; using System.Web; namespace Hello { /* * Use this class instead of `AuthTokens.None` when working with an IAM-auth-enabled server. * * Note that authentication happens only the first time for a pooled connection. * * Typical usage: * * var authToken = new NeptuneAuthToken(AccessKey, SecretKey, Region).GetAuthToken(Host); * _driver = GraphDatabase.Driver(Url, authToken, o => o.WithEncryptionLevel(EncryptionLevel.Encrypted)); */ public class NeptuneAuthToken { private const string ServiceName = "neptune-db"; private const string Scheme = "basic"; private const string Realm = "realm"; private const string DummyUserName = "username"; private const string Algorithm = "AWS4-HMAC-SHA256"; private const string AWSRequest = "aws4_request"; private readonly string _accessKey; private readonly string _secretKey; private readonly string _region; private readonly string _emptyPayloadHash; private readonly SHA256 _sha256; public NeptuneAuthToken(string awsKey = null, string secretKey = null, string region = null) { var awsCredentials = awsKey == null || secretKey == null ? FallbackCredentialsFactory.GetCredentials().GetCredentials() : null; _accessKey = awsKey ?? awsCredentials.AccessKey; _secretKey = secretKey ?? awsCredentials.SecretKey; _region = region ?? FallbackRegionFactory.GetRegionEndpoint().SystemName; //ex: us-east-1 _sha256 = SHA256.Create(); _emptyPayloadHash = Hash(Array.Empty<byte>()); } public IAuthToken GetAuthToken(string url) { return AuthTokens.Custom(DummyUserName, GetCredentials(url), Realm, Scheme); } /******************** AWS SIGNING FUNCTIONS *********************/ private string Hash(byte[] bytesToHash) { return ToHexString(_sha256.ComputeHash(bytesToHash)); } private static byte[] HmacSHA256(byte[] key, string data) { return new HMACSHA256(key).ComputeHash(Encoding.UTF8.GetBytes(data)); } private byte[] GetSignatureKey(string dateStamp) { var kSecret = Encoding.UTF8.GetBytes($"AWS4{_secretKey}"); var kDate = HmacSHA256(kSecret, dateStamp); var kRegion = HmacSHA256(kDate, _region); var kService = HmacSHA256(kRegion, ServiceName); return HmacSHA256(kService, AWSRequest); } private static string ToHexString(byte[] array) { return Convert.ToHexString(array).ToLowerInvariant(); } private string GetCredentials(string url) { var request = new HttpRequestMessage { Method = HttpMethod.Get, RequestUri = new Uri($"https://{url}/opencypher") }; var signedrequest = Sign(request); var headers = new Dictionary<string, object> { [HeaderKeys.AuthorizationHeader] = signedrequest.Headers.GetValues(HeaderKeys.AuthorizationHeader).FirstOrDefault(), ["HttpMethod"] = HttpMethod.Get.ToString(), [HeaderKeys.XAmzDateHeader] = signedrequest.Headers.GetValues(HeaderKeys.XAmzDateHeader).FirstOrDefault(), // Host should be capitalized, not like in Amazon.Util.HeaderKeys.HostHeader ["Host"] = signedrequest.Headers.GetValues(HeaderKeys.HostHeader).FirstOrDefault(), }; return JsonSerializer.Serialize(headers); } private HttpRequestMessage Sign(HttpRequestMessage request) { var now = DateTimeOffset.UtcNow; var amzdate = now.ToString("yyyyMMddTHHmmssZ"); var datestamp = now.ToString("yyyyMMdd"); if (request.Headers.Host == null) { request.Headers.Host = $"{request.RequestUri.Host}:{request.RequestUri.Port}"; } request.Headers.Add(HeaderKeys.XAmzDateHeader, amzdate); var canonicalQueryParams = GetCanonicalQueryParams(request); var canonicalRequest = new StringBuilder(); canonicalRequest.Append(request.Method + "\n"); canonicalRequest.Append(request.RequestUri.AbsolutePath + "\n"); canonicalRequest.Append(canonicalQueryParams + "\n"); var signedHeadersList = new List<string>(); foreach (var header in request.Headers.OrderBy(a => a.Key.ToLowerInvariant())) { canonicalRequest.Append(header.Key.ToLowerInvariant()); canonicalRequest.Append(':'); canonicalRequest.Append(string.Join(",", header.Value.Select(s => s.Trim()))); canonicalRequest.Append('\n'); signedHeadersList.Add(header.Key.ToLowerInvariant()); } canonicalRequest.Append('\n'); var signedHeaders = string.Join(";", signedHeadersList); canonicalRequest.Append(signedHeaders + "\n"); canonicalRequest.Append(_emptyPayloadHash); var credentialScope = $"{datestamp}/{_region}/{ServiceName}/{AWSRequest}"; var stringToSign = $"{Algorithm}\n{amzdate}\n{credentialScope}\n" + Hash(Encoding.UTF8.GetBytes(canonicalRequest.ToString())); var signing_key = GetSignatureKey(datestamp); var signature = ToHexString(HmacSHA256(signing_key, stringToSign)); request.Headers.TryAddWithoutValidation(HeaderKeys.AuthorizationHeader, $"{Algorithm} Credential={_accessKey}/{credentialScope}, SignedHeaders={signedHeaders}, Signature={signature}"); return request; } private static string GetCanonicalQueryParams(HttpRequestMessage request) { var querystring = HttpUtility.ParseQueryString(request.RequestUri.Query); // Query params must be escaped in upper case (i.e. "%2C", not "%2c"). var queryParams = querystring.AllKeys.OrderBy(a => a) .Select(key => $"{key}={Uri.EscapeDataString(querystring[key])}"); return string.Join("&", queryParams); } } }

認証で Bolt NETを使用して で openCypher クエリを作成する方法は次のとおりですIAM。次の例では、NeptuneAuthToken ヘルパーを使用しています。

using Neo4j.Driver; namespace Hello { public class HelloWorldExample { private const string Host = "(your hostname):8182"; private const string Url = $"bolt://{Host}"; private const string CreateNodeQuery = "CREATE (a:Greeting) SET a.message = 'HelloWorldExample'"; private const string ReadNodeQuery = "MATCH(n:Greeting) RETURN n.message"; private const string AccessKey = "(your access key)"; private const string SecretKey = "(your secret key)"; private const string Region = "(your AWS region)"; // e.g. "us-west-2" private readonly IDriver _driver; public HelloWorldExample() { var authToken = new NeptuneAuthToken(AccessKey, SecretKey, Region).GetAuthToken(Host); // Note that when the connection is reinitialized after max connection lifetime // has been reached, the signature token could have already been expired (usually 5 min) // You can face exceptions like: // `Unexpected server exception 'Signature expired: XXXX is now earlier than YYYY (ZZZZ - 5 min.)` _driver = GraphDatabase.Driver(Url, authToken, o => o.WithMaxConnectionLifetime(TimeSpan.FromMinutes(60)).WithEncryptionLevel(EncryptionLevel.Encrypted)); } public async Task CreateNode() { // Open a session using (var session = _driver.AsyncSession()) { // Run the query in a write transaction var greeting = await session.WriteTransactionAsync(async tx => { var result = await tx.RunAsync(CreateNodeQuery); // Consume the result return await result.ConsumeAsync(); }); // The output will look like this: // ResultSummary{Query=`CREATE (a:Greeting) SET a.message = 'HelloWorldExample"..... Console.WriteLine(greeting.Query); } } public async Task RetrieveNode() { // Open a session using (var session = _driver.AsyncSession()) { // Run the query in a read transaction var greeting = await session.ReadTransactionAsync(async tx => { var result = await tx.RunAsync(ReadNodeQuery); var records = await result.ToListAsync(); // Consume the result. Read the single node // created in a previous step. return records[0].Values.First().Value; }); // The output will look like this: // HelloWorldExample Console.WriteLine(greeting); } } } }

この例は、以下のコードを以下のパッケージで .NET 6 または .NET 7 に対して実行することで起動できます。

  • Neo4j.Driver=4.3.0

  • AWSSDK.Core=3.7.102.1

namespace Hello { class Program { static async Task Main() { var apiCaller = new HelloWorldExample(); await apiCaller.CreateNode(); await apiCaller.RetrieveNode(); } } }

Bolt とIAM認証を使用した Golang openCypher クエリの例

以下の Golang パッケージは、IAM認証で Bolt を使用して Go 言語で openCypher クエリを実行する方法を示しています。

package main import ( "context" "encoding/json" "fmt" "github.com/aws/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/signer/v4" "github.com/neo4j/neo4j-go-driver/v5/neo4j" "log" "net/http" "os" "time" ) const ( ServiceName = "neptune-db" DummyUsername = "username" ) // Find node by id using Go driver func findNode(ctx context.Context, region string, hostAndPort string, nodeId string) (string, error) { req, err := http.NewRequest(http.MethodGet, "https://"+hostAndPort+"/opencypher", nil) if err != nil { return "", fmt.Errorf("error creating request, %v", err) } // credentials must have been exported as environment variables signer := v4.NewSigner(credentials.NewEnvCredentials()) _, err = signer.Sign(req, nil, ServiceName, region, time.Now()) if err != nil { return "", fmt.Errorf("error signing request: %v", err) } hdrs := []string{"Authorization", "X-Amz-Date", "X-Amz-Security-Token"} hdrMap := make(map[string]string) for _, h := range hdrs { hdrMap[h] = req.Header.Get(h) } hdrMap["Host"] = req.Host hdrMap["HttpMethod"] = req.Method password, err := json.Marshal(hdrMap) if err != nil { return "", fmt.Errorf("error creating JSON, %v", err) } authToken := neo4j.BasicAuth(DummyUsername, string(password), "") // +s enables encryption with a full certificate check // Use +ssc to disable client side TLS verification driver, err := neo4j.NewDriverWithContext("bolt+s://"+hostAndPort+"/opencypher", authToken) if err != nil { return "", fmt.Errorf("error creating driver, %v", err) } defer driver.Close(ctx) if err := driver.VerifyConnectivity(ctx); err != nil { log.Fatalf("failed to verify connection, %v", err) } config := neo4j.SessionConfig{} session := driver.NewSession(ctx, config) defer session.Close(ctx) result, err := session.Run( ctx, fmt.Sprintf("MATCH (n) WHERE ID(n) = '%s' RETURN n", nodeId), map[string]any{}, ) if err != nil { return "", fmt.Errorf("error running query, %v", err) } if !result.Next(ctx) { return "", fmt.Errorf("node not found") } n, found := result.Record().Get("n") if !found { return "", fmt.Errorf("node not found") } return fmt.Sprintf("+%v\n", n), nil } func main() { if len(os.Args) < 3 { log.Fatal("Usage: go main.go (region) (host and port)") } region := os.Args[1] hostAndPort := os.Args[2] ctx := context.Background() res, err := findNode(ctx, region, hostAndPort, "72c2e8c1-7d5f-5f30-10ca-9d2bb8c4afbc") if err != nil { log.Fatal(err) } fmt.Println(res) }

Neptune での Bolt 接続動作

Neptune Bolt 接続に関する注意事項をいくつか次に示します。

  • Bolt 接続はTCPレイヤーで作成されるため、HTTPエンドポイントと同様に、その前に Application Load Balancer を使用することはできません。

  • Neptune が Bolt 接続に使用するポートは、DB クラスターのポートです。

  • 渡された Bolt プリアンブルに基づいて、Neptune サーバーは最適な Bolt バージョン (1、2、3、または 4.0) を選択します。

  • クライアントが任意の時点でオープンできる Neptune サーバーへの最大接続数は 1,000 です。

  • クエリの後にクライアントが接続を閉じない場合、その結合を使用して次のクエリを実行できます。

  • ただし、接続が 20 分間アイドル状態になると、サーバーは自動的に閉じます。

  • IAM 認証が有効になっていない場合は、ダミーのユーザー名とパスワードを指定するのAuthTokens.none()ではなく、 を使用できます。例えば、Java では次のようになります。

    GraphDatabase.driver("bolt://(your cluster endpoint URL):(your cluster port)", AuthTokens.none(), Config.builder().withEncryption().withTrustStrategy(TrustStrategy.trustSystemCertificates()).build());
  • IAM 認証が有効になっている場合、Bolt 接続は、他の理由でまだ閉じられていない場合、確立されてから 10 日以上後に常に数分切断されます。

  • クライアントが前のクエリの結果を消費せずに、接続を介して実行用のクエリを送信すると、新しいクエリは破棄されます。代わりに以前の結果を破棄するには、クライアントは接続を介してリセットメッセージを送信する必要があります。

  • 特定の接続では、一度に作成できるトランザクションは 1 つだけです。

  • トランザクション中に例外が発生すると、Neptune サーバーはトランザクションをロールバックし、接続を閉じます。この場合、ドライバーは次のクエリ用に新しい接続を作成します。

  • セッションはスレッドセーフではないことに注意してください。複数の並列操作では、複数の別々のセッションを使用する必要があります。