Utilizzo del protocollo Bolt per effettuare openCypher interrogazioni a Neptune - Amazon Neptune

Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.

Utilizzo del protocollo Bolt per effettuare openCypher interrogazioni a Neptune

Bolt è un protocollo client/server orientato alle istruzioni inizialmente sviluppato da Neo4j e concesso in licenza con la licenza Creative Commons 3.0 Attribution-. ShareAlike È basato sul client, il che significa che il client avvia sempre lo scambio di messaggi.

Per connettersi a Neptune utilizzando i driver Bolt di Neo4j, è sufficiente sostituire URL il numero di porta and con gli endpoint del cluster utilizzando lo schema. bolt URI Se è in esecuzione una singola istanza di Neptune, usare l'endpoint read_write. Se sono in esecuzione più istanze, si consigliano due driver, uno per la scrittura e l'altro per tutte le repliche di lettura. Se si dispone solo dei due endpoint predefiniti, sono sufficienti un driver read_write e uno read_only, ma se si dispone anche di endpoint personalizzati, valutare la possibilità di creare un'istanza del driver per ciascuno di essi.

Nota

Sebbene le specifiche Bolt affermino che Bolt può connettersi utilizzando uno dei due oTCP, WebSockets Neptune supporta solo connessioni per Bolt. TCP

Neptune consente fino a 1.000 connessioni Bolt simultanee.

Per esempi di openCypher query in varie lingue che utilizzano i driver Bolt, consulta la documentazione Neo4j Drivers & Language Guides.

Importante

I driver Neo4j Bolt per Python,. NET JavaScript, e inizialmente Golang non supportava il rinnovo automatico di AWS Token di autenticazione Signature v4. Ciò significa che dopo la scadenza della firma (spesso dopo 5 minuti), il driver non riusciva ad autenticarsi e le richieste successive avevano esito negativo. Il Python,. NET, JavaScript, e gli esempi di Go riportati di seguito sono stati tutti interessati da questo problema.

Vedi il numero #834 del driver Python Neo4j, Neo4j. NETnumero #664, numero #993 del driver Neo4j e numero #429 del JavaScript driver goLang Neo4j per maggiori informazioni.

A partire dalla versione 5.8.0 del driver, API è stata rilasciata una nuova riautenticazione in anteprima per il driver Go (vedere v5.8.0 - Desiderio di feedback sulla riautenticazione).

Utilizzo di Bolt con Java per connettersi a Neptune

Puoi scaricare un driver per qualsiasi versione che desideri utilizzare dal MVNrepository Maven o aggiungere questa dipendenza al tuo progetto:

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

Quindi, per connettersi a Neptune in Java utilizzando uno di questi driver Bolt, creare un'istanza del driver per l'istanza primaria/di scrittura nel cluster usando un codice simile al seguente:

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());

Se si dispone di una o più repliche di lettura, è possibile creare in modo analogo un'istanza del driver per tali repliche utilizzando un codice simile al seguente:

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());

Oppure, con un timeout:

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());

Se si dispone di endpoint personalizzati, può anche essere utile creare un'istanza del driver per ognuno di essi.

Un esempio di openCypher query in Python che utilizza Bolt

Ecco come creare una openCypher query in Python usando Bolt:

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)

Notare che i parametri auth vengono ignorati.

A. NET openCypher esempio di interrogazione con Bolt

Per effettuare un' openCypher interrogazione. NETusando Bolt, il primo passo è installare il driver Neo4j usando. NuHet Per effettuare chiamate sincrone, usare la versione .Simple, come in questo caso:

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(); } } } }

Un esempio di openCypher query Java che utilizza Bolt con autenticazione IAM

Il codice Java riportato di seguito mostra come effettuare openCypher interrogazioni in Java utilizzando Bolt con autenticazione. IAM Il JavaDoc commento ne descrive l'utilizzo. Una volta disponibile un'istanza del driver, è possibile utilizzarla per effettuare più richieste autenticate.

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); } }

Un esempio di openCypher query in Python che utilizza Bolt con autenticazione IAM

La classe Python seguente consente di effettuare openCypher query in Python utilizzando Bolt con autenticazione: IAM

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)

Utilizzare questa classe per creare un driver come segue:

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

Un esempio di Node.js che utilizza l'autenticazione e Bolt IAM

Il codice Node.js riportato di seguito utilizza AWS SDKper la JavaScript versione 3 e la ES6 sintassi per creare un driver che autentichi le richieste:

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); });

A. NET openCypher esempio di interrogazione che utilizza Bolt con autenticazione IAM

Per abilitare IAM l'autenticazione in. NET, è necessario firmare una richiesta quando si stabilisce la connessione. L'esempio seguente mostra come creare un helper NeptuneAuthToken per generare un token di autenticazione:

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); } } }

Ecco come effettuare un' openCypher interrogazione in. NETutilizzo di Bolt con IAM autenticazione. L'esempio seguente utilizza l'helper 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); } } } }

Questo esempio può essere avviato eseguendo il codice sottostante su .NET 6 o .NET 7 con i seguenti pacchetti:

  • 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(); } } }

Un esempio di openCypher interrogazione Golang che utilizza Bolt con autenticazione IAM

Il pacchetto Golang seguente mostra come effettuare openCypher interrogazioni in lingua Go usando Bolt con autenticazione: IAM

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) }

Comportamento della connessione Bolt in Neptune

Di seguito sono elencati alcuni punti da tenere a mente sulle connessioni Bolt in Neptune:

  • Poiché le connessioni Bolt vengono create a TCP livello, non è possibile utilizzare un Application Load Balancer davanti a esse, come con HTTP un endpoint.

  • La porta utilizzata da Neptune per le connessioni Bolt è la porta del cluster database.

  • In base al preambolo Bolt che gli è stato passato, il server Neptune seleziona la versione Bolt più elevata appropriata (1, 2, 3 o 4.0).

  • Il numero massimo di connessioni al server Neptune che un client può avere aperte in qualsiasi momento è 1.000.

  • Se il client non chiude una connessione dopo una query, tale connessione può essere utilizzata per eseguire la query successiva.

  • Tuttavia, se una connessione rimane inattiva per 20 minuti, il server la chiude automaticamente.

  • Se IAM l'autenticazione non è abilitata, è possibile utilizzare, AuthTokens.none() anziché fornire, un nome utente e una password fittizi. Ad esempio, in Java:

    GraphDatabase.driver("bolt://(your cluster endpoint URL):(your cluster port)", AuthTokens.none(), Config.builder().withEncryption().withTrustStrategy(TrustStrategy.trustSystemCertificates()).build());
  • Quando IAM l'autenticazione è abilitata, una connessione Bolt viene sempre disconnessa alcuni minuti e più di 10 giorni dopo essere stata stabilita, a meno che non sia già stata chiusa per qualche altro motivo.

  • Se il client invia una query per l'esecuzione tramite una connessione senza aver utilizzato i risultati di una query precedente, la nuova query viene eliminata. Per eliminare invece i risultati precedenti, il client deve inviare un messaggio di ripristino tramite la connessione.

  • Su una determinata connessione è possibile creare una sola transazione alla volta.

  • Se si verifica un'eccezione durante una transazione, il server Neptune esegue il rollback della transazione e chiude la connessione. In questo caso, il driver crea una nuova connessione per la query successiva.

  • Tenere presente che le sessioni non sono thread-safe. Più operazioni parallele devono utilizzare più sessioni separate.