From d6316a80a6b7406db85597bcffe2b67f277aee06 Mon Sep 17 00:00:00 2001 From: Chloe Date: Mon, 25 Nov 2024 20:13:56 +0000 Subject: [PATCH 1/9] java examples Signed-off-by: Chloe --- .../java/glide/examples/GlideFtExample.java | 179 ++++++++++++++++++ .../java/glide/examples/GlideJsonExample.java | 134 +++++++++++++ 2 files changed, 313 insertions(+) create mode 100644 examples/java/src/main/java/glide/examples/GlideFtExample.java create mode 100644 examples/java/src/main/java/glide/examples/GlideJsonExample.java diff --git a/examples/java/src/main/java/glide/examples/GlideFtExample.java b/examples/java/src/main/java/glide/examples/GlideFtExample.java new file mode 100644 index 0000000000..1e8cac2df4 --- /dev/null +++ b/examples/java/src/main/java/glide/examples/GlideFtExample.java @@ -0,0 +1,179 @@ +/** Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0 */ +package glide.examples; + +import static glide.api.logging.Logger.Level.ERROR; +import static glide.api.logging.Logger.Level.INFO; +import static glide.api.logging.Logger.Level.WARN; +import static glide.api.logging.Logger.log; + +import glide.api.GlideClient; +import glide.api.commands.servermodules.FT; + +import glide.api.logging.Logger; +import glide.api.models.configuration.GlideClientConfiguration; +import glide.api.models.configuration.NodeAddress; +import glide.api.models.exceptions.ClosingException; +import glide.api.models.exceptions.ConnectionException; +import glide.api.models.exceptions.TimeoutException; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +public class GlideFtExample { + + /** + * Creates and returns a GlideClient instance. + * + *

This function initializes a GlideClient with the provided list of nodes. The + * list may contain either only primary node or a mix of primary and replica nodes. The + * GlideClient + * use these nodes to connect to the Standalone setup servers. + * + * @return A GlideClient connected to the provided node address. + * @throws CancellationException if the operation is cancelled. + * @throws ExecutionException if the client fails due to execution errors. + * @throws InterruptedException if the operation is interrupted. + */ + public static GlideClient createClient(List nodeList) + throws CancellationException, ExecutionException, InterruptedException { + // Check `GlideClientConfiguration` for additional options. + GlideClientConfiguration config = + GlideClientConfiguration.builder() + .addresses(nodeList) + // Enable this field if the servers are configured with TLS. + // .useTLS(true); + .build(); + + GlideClient client = GlideClient.createClient(config).get(); + return client; + } + + /** + * Executes the main logic of the application, performing basic operations such as SET, GET, and + * PING using the provided GlideClient. + * + * @param client An instance of GlideClient. + * @throws ExecutionException if an execution error occurs during operations. + * @throws InterruptedException if the operation is interrupted. + */ + public static void appLogic(GlideClient client) throws ExecutionException, InterruptedException { + + // Create a vector + CompletableFuture create = FT.create( + client, + index, + new FieldInfo[] { + new FieldInfo("vec", "VEC", VectorFieldHnsw.builder(DistanceMetric.L2, 2).build()) + }, + FTCreateOptions.builder() + .dataType(DataType.HASH) + .prefixes(new String[] {prefix}) + .build()); + // The response should be "OK" + + // Search options for the vector + var options = + FTSearchOptions.builder() + .params( + Map.of( + gs("query_vec"), + gs( + new byte[] { + (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, + (byte) 0 + }))) + .build(); + // Search for the vector + CompletableFuture search = FT.search(client, index, "*=>[KNN 2 @VEC $query_vec]", options); + // The response should be + // 2L, + // Map.of( + // gs(prefix + 0), + // Map.of(gs("__VEC_score"), gs("0"), gs("vec"), gs("\0\0\0\0\0\0\0\0")), + // gs(prefix + 1), + // Map.of( + // gs("__VEC_score"), + // gs("1"), + // gs("vec"), + // gs( + // new byte[] { + // (byte) 0, + // (byte) 0, + // (byte) 0, + // (byte) 0, + // (byte) 0, + // (byte) 0, + // (byte) 0x80, + // (byte) 0xBF + // }))) + } + + /** + * Executes the application logic with exception handling. + * + * @throws ExecutionException if an execution error occurs during operations. + */ + private static void execAppLogic() throws ExecutionException { + + // Define list of nodes + List nodeList = + Collections.singletonList(NodeAddress.builder().host("localhost").port(6379).build()); + + while (true) { + try (GlideClient client = createClient(nodeList)) { + appLogic(client); + return; + } catch (CancellationException e) { + log(ERROR, "glide", "Request cancelled: " + e.getMessage()); + throw e; + } catch (InterruptedException e) { + log(ERROR, "glide", "Client interrupted: " + e.getMessage()); + Thread.currentThread().interrupt(); // Restore interrupt status + throw new CancellationException("Client was interrupted."); + } catch (ExecutionException e) { + // All Glide errors will be handled as ExecutionException + if (e.getCause() instanceof ClosingException) { + // If the error message contains "NOAUTH", raise the exception + // because it indicates a critical authentication issue. + if (e.getMessage().contains("NOAUTH")) { + log(ERROR, "glide", "Authentication error encountered: " + e.getMessage()); + throw e; + } else { + log(WARN, "glide", "Client has closed and needs to be re-created: " + e.getMessage()); + } + } else if (e.getCause() instanceof ConnectionException) { + // The client wasn't able to reestablish the connection within the given retries + log(ERROR, "glide", "Connection error encountered: " + e.getMessage()); + throw e; + } else if (e.getCause() instanceof TimeoutException) { + // A request timed out. You may choose to retry the execution based on your application's + // logic + log(ERROR, "glide", "Timeout encountered: " + e.getMessage()); + throw e; + } else { + log(ERROR, "glide", "Execution error encountered: " + e.getCause()); + throw e; + } + } + } + } + + /** + * The entry point of the standalone example. This method sets up the logger configuration and + * executes the main application logic. + * + * @param args Command-line arguments passed to the application. + * @throws ExecutionException if an error occurs during execution of the application logic. + */ + public static void main(String[] args) throws ExecutionException { + // In this example, we will utilize the client's logger for all log messages + Logger.setLoggerConfig(INFO); + // Optional - set the logger to write to a file + // Logger.setLoggerConfig(Logger.Level.INFO, file) + execAppLogic(); + } +} diff --git a/examples/java/src/main/java/glide/examples/GlideJsonExample.java b/examples/java/src/main/java/glide/examples/GlideJsonExample.java new file mode 100644 index 0000000000..2eb068133d --- /dev/null +++ b/examples/java/src/main/java/glide/examples/GlideJsonExample.java @@ -0,0 +1,134 @@ +/** Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0 */ +package glide.examples; + +import static glide.api.logging.Logger.Level.ERROR; +import static glide.api.logging.Logger.Level.INFO; +import static glide.api.logging.Logger.Level.WARN; +import static glide.api.logging.Logger.log; + +import glide.api.GlideClient; +import glide.api.commands.servermodules.Json; +import glide.api.logging.Logger; +import glide.api.models.configuration.GlideClientConfiguration; +import glide.api.models.configuration.NodeAddress; +import glide.api.models.exceptions.ClosingException; +import glide.api.models.exceptions.ConnectionException; +import glide.api.models.exceptions.TimeoutException; + +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +public class GlideJsonExample { + + /** + * Creates and returns a GlideClient instance. + * + *

This function initializes a GlideClient with the provided list of nodes. The + * list may contain either only primary node or a mix of primary and replica nodes. The + * GlideClient + * use these nodes to connect to the Standalone setup servers. + * + * @return A GlideClient connected to the provided node address. + * @throws CancellationException if the operation is cancelled. + * @throws ExecutionException if the client fails due to execution errors. + * @throws InterruptedException if the operation is interrupted. + */ + public static GlideClient createClient(List nodeList) + throws CancellationException, ExecutionException, InterruptedException { + // Check `GlideClientConfiguration` for additional options. + GlideClientConfiguration config = + GlideClientConfiguration.builder() + .addresses(nodeList) + // Enable this field if the servers are configured with TLS. + // .useTLS(true); + .build(); + + GlideClient client = GlideClient.createClient(config).get(); + return client; + } + + /** + * Executes the main logic of the application, performing basic operations such as SET, GET, and + * PING using the provided GlideClusterClient. + * + * @param client An instance of GlideClusterClient. + * @throws ExecutionException if an execution error occurs during operations. + * @throws InterruptedException if the operation is interrupted. + */ + public static void appLogic(GlideClusterClient client) throws ExecutionException, InterruptedException { + + CompletableFuture setResponse = Json.set(client, key, "$", "{\"a\": 1.0,\"b\": 2}"); + System.out.println("The set response is " + setResponse.get()); // The response should be "OK" + + CompletableFuture getResponse = Json.get(client, key, "$.a", "$.b"); + System.out.println("The get response is " + getResponse.get()); // The response should be "{\"$.a\":[1.0],\"$.b\":[2]}" + } + + /** + * Executes the application logic with exception handling. + * + * @throws ExecutionException if an execution error occurs during operations. + */ + private static void execAppLogic() throws ExecutionException { + + // Define list of nodes + List nodeList = + Collections.singletonList(NodeAddress.builder().host("localhost").port(6379).build()); + + while (true) { + try (GlideClient client = createClient(nodeList)) { + appLogic(client); + return; + } catch (CancellationException e) { + log(ERROR, "glide", "Request cancelled: " + e.getMessage()); + throw e; + } catch (InterruptedException e) { + log(ERROR, "glide", "Client interrupted: " + e.getMessage()); + Thread.currentThread().interrupt(); // Restore interrupt status + throw new CancellationException("Client was interrupted."); + } catch (ExecutionException e) { + // All Glide errors will be handled as ExecutionException + if (e.getCause() instanceof ClosingException) { + // If the error message contains "NOAUTH", raise the exception + // because it indicates a critical authentication issue. + if (e.getMessage().contains("NOAUTH")) { + log(ERROR, "glide", "Authentication error encountered: " + e.getMessage()); + throw e; + } else { + log(WARN, "glide", "Client has closed and needs to be re-created: " + e.getMessage()); + } + } else if (e.getCause() instanceof ConnectionException) { + // The client wasn't able to reestablish the connection within the given retries + log(ERROR, "glide", "Connection error encountered: " + e.getMessage()); + throw e; + } else if (e.getCause() instanceof TimeoutException) { + // A request timed out. You may choose to retry the execution based on your application's + // logic + log(ERROR, "glide", "Timeout encountered: " + e.getMessage()); + throw e; + } else { + log(ERROR, "glide", "Execution error encountered: " + e.getCause()); + throw e; + } + } + } + } + + /** + * The entry point of the standalone example. This method sets up the logger configuration and + * executes the main application logic. + * + * @param args Command-line arguments passed to the application. + * @throws ExecutionException if an error occurs during execution of the application logic. + */ + public static void main(String[] args) throws ExecutionException { + // In this example, we will utilize the client's logger for all log messages + Logger.setLoggerConfig(INFO); + // Optional - set the logger to write to a file + // Logger.setLoggerConfig(Logger.Level.INFO, file) + execAppLogic(); + } +} From 466d6c2dbf6c456e9da8c77b6d9f6a23d5497e8a Mon Sep 17 00:00:00 2001 From: Chloe Date: Tue, 26 Nov 2024 18:16:51 +0000 Subject: [PATCH 2/9] finished implementing tests, test against memorydb instance Signed-off-by: Chloe --- .../java/glide/examples/GlideFtExample.java | 5 +- .../java/glide/examples/GlideJsonExample.java | 5 +- examples/python/ft_example.py | 145 ++++++++++++++++++ examples/python/json_example.py | 130 ++++++++++++++++ 4 files changed, 281 insertions(+), 4 deletions(-) create mode 100644 examples/python/ft_example.py create mode 100644 examples/python/json_example.py diff --git a/examples/java/src/main/java/glide/examples/GlideFtExample.java b/examples/java/src/main/java/glide/examples/GlideFtExample.java index 1e8cac2df4..1d1947cba8 100644 --- a/examples/java/src/main/java/glide/examples/GlideFtExample.java +++ b/examples/java/src/main/java/glide/examples/GlideFtExample.java @@ -53,8 +53,7 @@ public static GlideClient createClient(List nodeList) } /** - * Executes the main logic of the application, performing basic operations such as SET, GET, and - * PING using the provided GlideClient. + * Executes the main logic of the application, performing basic operations such as FT.CREATE and FT.SEARCH using the provided GlideClient. * * @param client An instance of GlideClient. * @throws ExecutionException if an execution error occurs during operations. @@ -62,6 +61,8 @@ public static GlideClient createClient(List nodeList) */ public static void appLogic(GlideClient client) throws ExecutionException, InterruptedException { + // TODO: test example against memorydb instance + // Create a vector CompletableFuture create = FT.create( client, diff --git a/examples/java/src/main/java/glide/examples/GlideJsonExample.java b/examples/java/src/main/java/glide/examples/GlideJsonExample.java index 2eb068133d..2e21feea3e 100644 --- a/examples/java/src/main/java/glide/examples/GlideJsonExample.java +++ b/examples/java/src/main/java/glide/examples/GlideJsonExample.java @@ -51,14 +51,15 @@ public static GlideClient createClient(List nodeList) } /** - * Executes the main logic of the application, performing basic operations such as SET, GET, and - * PING using the provided GlideClusterClient. + * Executes the main logic of the application, performing basic operations such as JSON.SET and JSON.GET using the provided GlideClusterClient. * * @param client An instance of GlideClusterClient. * @throws ExecutionException if an execution error occurs during operations. * @throws InterruptedException if the operation is interrupted. */ public static void appLogic(GlideClusterClient client) throws ExecutionException, InterruptedException { + + // TODO: test example against memorydb instance CompletableFuture setResponse = Json.set(client, key, "$", "{\"a\": 1.0,\"b\": 2}"); System.out.println("The set response is " + setResponse.get()); // The response should be "OK" diff --git a/examples/python/ft_example.py b/examples/python/ft_example.py new file mode 100644 index 0000000000..500c09c646 --- /dev/null +++ b/examples/python/ft_example.py @@ -0,0 +1,145 @@ +import asyncio +from typing import List, Tuple + +from glide import ( + ClosingError, + ConnectionError, + GlideClient, + GlideClientConfiguration, + Logger, + LogLevel, + NodeAddress, + RequestError, + TimeoutError +) + +from python.glade.async_commands.server_modules import ft +from glide.async_commands.server_modules.ft_options.ft_search_options import ( + FtSearchOptions, +) + +async def create_client( + nodes_list: List[Tuple[str, int]] = [("localhost", 6379)] +) -> GlideClient: + """ + Creates and returns a GlideClient instance. + + This function initializes a GlideClient with the provided list of nodes. + The nodes_list may contain either only primary node or a mix of primary + and replica nodes. The GlideClient use these nodes to connect to + the Standalone setup servers. + + Args: + nodes_list (List[Tuple[str, int]]): A list of tuples where each tuple + contains a host (str) and port (int). Defaults to [("localhost", 6379)]. + + Returns: + GlideClient: An instance of GlideClient connected to the specified nodes. + """ + addresses = [] + for host, port in nodes_list: + addresses.append(NodeAddress(host, port)) + + # Check `GlideClientConfiguration` for additional options. + config = GlideClientConfiguration( + addresses, + # Enable this field if the servers are configured with TLS. + # use_tls=True + ) + return await GlideClient.create(config) + + +async def app_logic(client: GlideClusterClient): + """ + Executes the main logic of the application, performing basic operations + such as FT.CREATE and FT.SEARCH using the provided GlideClient. + + Args: + client (GlideClusterClient): An instance of GlideClient. + """ + + # TODO: test against memory db instance + + # Create a vector + create_response = await ft.create(client, "index", + schema=[ + NumericField("$.a", "a"), + NumericField("$.b", "b"), + ], + options=FtCreateOptions(DataType.JSON), + ) + Logger.log(LogLevel.INFO, "app", f"Create response is = {create_response!r}") + + # Search for the vector + search_response = await ft.search(glide_client, index, "*", options=ft_search_options) + ft_search_options = FtSearchOptions( + return_fields=[ + ReturnField(field_identifier="a", alias="a_new"), + ReturnField(field_identifier="b", alias="b_new"), + ] + ) + + Logger.log(LogLevel.INFO, "app", f"Search response is = {search_response!r}") + + +async def exec_app_logic(): + """ + Executes the application logic with exception handling. + """ + while True: + try: + client = await create_client() + return await app_logic(client) + except asyncio.CancelledError: + raise + except ClosingError as e: + # If the error message contains "NOAUTH", raise the exception + # because it indicates a critical authentication issue. + if "NOAUTH" in str(e): + Logger.log( + LogLevel.ERROR, + "glide", + f"Authentication error encountered: {e}", + ) + raise e + Logger.log( + LogLevel.WARN, + "glide", + f"Client has closed and needs to be re-created: {e}", + ) + except TimeoutError as e: + # A request timed out. You may choose to retry the execution based on your application's logic + Logger.log(LogLevel.ERROR, "glide", f"TimeoutError encountered: {e}") + raise e + except ConnectionError as e: + # The client wasn't able to reestablish the connection within the given retries + Logger.log(LogLevel.ERROR, "glide", f"ConnectionError encountered: {e}") + raise e + except RequestError as e: + # Other error reported during a request, such as a server response error + Logger.log(LogLevel.ERROR, "glide", f"RequestError encountered: {e}") + raise e + except Exception as e: + Logger.log(LogLevel.ERROR, "glide", f"Unexpected error: {e}") + raise e + finally: + try: + await client.close() + except Exception as e: + Logger.log( + LogLevel.WARN, + "glide", + f"Encountered an error while closing the client: {e}", + ) + + +def main(): + # In this example, we will utilize the client's logger for all log messages + Logger.set_logger_config(LogLevel.INFO) + # Optional - set the logger to write to a file + # Logger.set_logger_config(LogLevel.INFO, file) + asyncio.run(exec_app_logic()) + + +if __name__ == "__main__": + main() diff --git a/examples/python/json_example.py b/examples/python/json_example.py new file mode 100644 index 0000000000..4c058ca04e --- /dev/null +++ b/examples/python/json_example.py @@ -0,0 +1,130 @@ +import asyncio +from typing import List, Tuple + +from glide import ( + ClosingError, + ConnectionError, + GlideClient, + GlideClientConfiguration, + Logger, + LogLevel, + NodeAddress, + RequestError, + TimeoutError +) + +from python.glade.async_commands.server_modules import glide_json + + +async def create_client( + nodes_list: List[Tuple[str, int]] = [("localhost", 6379)] +) -> GlideClient: + """ + Creates and returns a GlideClient instance. + + This function initializes a GlideClient with the provided list of nodes. + The nodes_list may contain either only primary node or a mix of primary + and replica nodes. The GlideClient use these nodes to connect to + the Standalone setup servers. + + Args: + nodes_list (List[Tuple[str, int]]): A list of tuples where each tuple + contains a host (str) and port (int). Defaults to [("localhost", 6379)]. + + Returns: + GlideClient: An instance of GlideClient connected to the specified nodes. + """ + addresses = [] + for host, port in nodes_list: + addresses.append(NodeAddress(host, port)) + + # Check `GlideClientConfiguration` for additional options. + config = GlideClientConfiguration( + addresses, + # Enable this field if the servers are configured with TLS. + # use_tls=True + ) + return await GlideClient.create(config) + + +async def app_logic(client: TGlideClient): + """ + Executes the main logic of the application, performing basic operations + such as JSON.SET and JSON.GET using the provided GlideClient. + + Args: + client (TGlideClient): An instance of GlideClient. + """ + + # TODO: test against memory db instance + + json_value = {"a": 1.0, "b": 2} + # Send SET and GET + set_response = await json.set(client, "key", "$") + Logger.log(LogLevel.INFO, "app", f"Set response is = {set_response!r}") + + get_response = await json.get(client, "key", "$") + Logger.log(LogLevel.INFO, "app", f"Get response is = {get_response.decode()!r}") + + +async def exec_app_logic(): + """ + Executes the application logic with exception handling. + """ + while True: + try: + client = await create_client() + return await app_logic(client) + except asyncio.CancelledError: + raise + except ClosingError as e: + # If the error message contains "NOAUTH", raise the exception + # because it indicates a critical authentication issue. + if "NOAUTH" in str(e): + Logger.log( + LogLevel.ERROR, + "glide", + f"Authentication error encountered: {e}", + ) + raise e + Logger.log( + LogLevel.WARN, + "glide", + f"Client has closed and needs to be re-created: {e}", + ) + except TimeoutError as e: + # A request timed out. You may choose to retry the execution based on your application's logic + Logger.log(LogLevel.ERROR, "glide", f"TimeoutError encountered: {e}") + raise e + except ConnectionError as e: + # The client wasn't able to reestablish the connection within the given retries + Logger.log(LogLevel.ERROR, "glide", f"ConnectionError encountered: {e}") + raise e + except RequestError as e: + # Other error reported during a request, such as a server response error + Logger.log(LogLevel.ERROR, "glide", f"RequestError encountered: {e}") + raise e + except Exception as e: + Logger.log(LogLevel.ERROR, "glide", f"Unexpected error: {e}") + raise e + finally: + try: + await client.close() + except Exception as e: + Logger.log( + LogLevel.WARN, + "glide", + f"Encountered an error while closing the client: {e}", + ) + + +def main(): + # In this example, we will utilize the client's logger for all log messages + Logger.set_logger_config(LogLevel.INFO) + # Optional - set the logger to write to a file + # Logger.set_logger_config(LogLevel.INFO, file) + asyncio.run(exec_app_logic()) + + +if __name__ == "__main__": + main() From 0dedde50e844f0281224b3fdf276d23afa13009e Mon Sep 17 00:00:00 2001 From: Chloe Date: Tue, 26 Nov 2024 21:18:18 +0000 Subject: [PATCH 3/9] update ftexample and changed java json example to do cluster Signed-off-by: Chloe --- .../java/glide/examples/GlideFtExample.java | 184 +++++++++++------- .../java/glide/examples/GlideJsonExample.java | 59 +++--- 2 files changed, 151 insertions(+), 92 deletions(-) diff --git a/examples/java/src/main/java/glide/examples/GlideFtExample.java b/examples/java/src/main/java/glide/examples/GlideFtExample.java index 1d1947cba8..125c4a998a 100644 --- a/examples/java/src/main/java/glide/examples/GlideFtExample.java +++ b/examples/java/src/main/java/glide/examples/GlideFtExample.java @@ -5,20 +5,22 @@ import static glide.api.logging.Logger.Level.INFO; import static glide.api.logging.Logger.Level.WARN; import static glide.api.logging.Logger.log; +import static glide.api.models.configuration.RequestRoutingConfiguration.SimpleMultiNodeRoute.ALL_NODES; -import glide.api.GlideClient; +import glide.api.GlideClusterClient; import glide.api.commands.servermodules.FT; - import glide.api.logging.Logger; -import glide.api.models.configuration.GlideClientConfiguration; +import glide.api.models.ClusterValue; +import glide.api.models.commands.InfoOptions.Section; +import glide.api.models.configuration.GlideClusterClientConfiguration; import glide.api.models.configuration.NodeAddress; import glide.api.models.exceptions.ClosingException; import glide.api.models.exceptions.ConnectionException; import glide.api.models.exceptions.TimeoutException; - import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.UUID; import java.util.concurrent.CancellationException; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; @@ -26,91 +28,137 @@ public class GlideFtExample { /** - * Creates and returns a GlideClient instance. + * Creates and returns a GlideClusterClient instance. * - *

This function initializes a GlideClient with the provided list of nodes. The - * list may contain either only primary node or a mix of primary and replica nodes. The - * GlideClient - * use these nodes to connect to the Standalone setup servers. + *

This function initializes a GlideClusterClient with the provided list of nodes. + * The list may contain the address of one or more cluster nodes, and the client will + * automatically discover all nodes in the cluster. * - * @return A GlideClient connected to the provided node address. + * @return A GlideClusterClient connected to the discovered nodes. * @throws CancellationException if the operation is cancelled. * @throws ExecutionException if the client fails due to execution errors. * @throws InterruptedException if the operation is interrupted. */ - public static GlideClient createClient(List nodeList) + public static GlideClusterClient createClient(List nodeList) throws CancellationException, ExecutionException, InterruptedException { - // Check `GlideClientConfiguration` for additional options. - GlideClientConfiguration config = - GlideClientConfiguration.builder() + // Check `GlideClusterClientConfiguration` for additional options. + GlideClusterClientConfiguration config = + GlideClusterClientConfiguration.builder() .addresses(nodeList) // Enable this field if the servers are configured with TLS. // .useTLS(true); .build(); - GlideClient client = GlideClient.createClient(config).get(); + GlideClusterClient client = GlideClusterClient.createClient(config).get(); return client; } /** - * Executes the main logic of the application, performing basic operations such as FT.CREATE and FT.SEARCH using the provided GlideClient. + * Executes the main logic of the application, performing basic operations such as FT.CREATE and + * FT.SEARCH using the provided GlideClusterClient. * - * @param client An instance of GlideClient. + * @param client An instance of GlideClusterClient. * @throws ExecutionException if an execution error occurs during operations. * @throws InterruptedException if the operation is interrupted. */ - public static void appLogic(GlideClient client) throws ExecutionException, InterruptedException { - - // TODO: test example against memorydb instance - - // Create a vector - CompletableFuture create = FT.create( - client, - index, - new FieldInfo[] { - new FieldInfo("vec", "VEC", VectorFieldHnsw.builder(DistanceMetric.L2, 2).build()) - }, - FTCreateOptions.builder() - .dataType(DataType.HASH) - .prefixes(new String[] {prefix}) - .build()); - // The response should be "OK" - - // Search options for the vector - var options = - FTSearchOptions.builder() - .params( + public static void appLogic(GlideClusterClient client) + throws ExecutionException, InterruptedException { + + String prefix = "{" + UUID.randomUUID() + "}:"; + String index = prefix + "index"; + + CompletableFuture createResponse = + FT.create( + client, + index, + new FieldInfo[] { + new FieldInfo("vec", "VEC", VectorFieldHnsw.builder(DistanceMetric.L2, 2).build()) + }, + FTCreateOptions.builder() + .dataType(DataType.HASH) + .prefixes(new String[] {prefix}) + .build()); // ok + + CompletableFuture hsetResponse = + client.hset( + gs(prefix + 0), + Map.of( + gs("vec"), + gs( + new byte[] { + (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0 + }))); // response is 1L which represents the number of fields that were added. + + hsetResponse = + client.hset( + gs(prefix + 1), Map.of( - gs("query_vec"), + gs("vec"), gs( new byte[] { - (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, - (byte) 0 - }))) - .build(); - // Search for the vector - CompletableFuture search = FT.search(client, index, "*=>[KNN 2 @VEC $query_vec]", options); - // The response should be - // 2L, - // Map.of( - // gs(prefix + 0), - // Map.of(gs("__VEC_score"), gs("0"), gs("vec"), gs("\0\0\0\0\0\0\0\0")), - // gs(prefix + 1), - // Map.of( - // gs("__VEC_score"), - // gs("1"), - // gs("vec"), - // gs( - // new byte[] { - // (byte) 0, - // (byte) 0, - // (byte) 0, - // (byte) 0, - // (byte) 0, - // (byte) 0, - // (byte) 0x80, - // (byte) 0xBF - // }))) + (byte) 0, + (byte) 0, + (byte) 0, + (byte) 0, + (byte) 0, + (byte) 0, + (byte) 0x80, + (byte) 0xBF + }))); // response is 1L which represents the number of fields that were added. + Thread.sleep(DATA_PROCESSING_TIMEOUT); // let server digest the data and update + + // These are the optional arguments used for the FT.search command + var options = + FTSearchOptions.builder() + .params( + Map.of( + gs("query_vec"), + gs( + new byte[] { + (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, + (byte) 0 + }))) + .build(); + String query = "*=>[KNN 2 @VEC $query_vec]"; // This is the text query to search for + CompletableFuture searchResponse = FT.search(client, index, query, options); + + // When you call .get() on searchResponse, the result will be an Object[] as shown in the commented assert test below. + // assertArrayEquals( + // new Object[] { + // 2L, + // Map.of( + // gs(prefix + 0), + // Map.of(gs("__VEC_score"), gs("0"), gs("vec"), gs("\0\0\0\0\0\0\0\0")), + // gs(prefix + 1), + // Map.of( + // gs("__VEC_score"), + // gs("1"), + // gs("vec"), + // gs( + // new byte[] { + // (byte) 0, + // (byte) 0, + // (byte) 0, + // (byte) 0, + // (byte) 0, + // (byte) 0, + // (byte) 0x80, + // (byte) 0xBF + // }))) + // }, + // searchResponse.get()); + + System.out.println("Create response: " + createResponse.get()); + System.out.println("Hset response: " + hsetResponse.get()); + System.out.println("Search response: " + searchResponse.get()); + + // Send INFO REPLICATION with routing option to all nodes + ClusterValue infoResponse = + client.info(new Section[] {Section.REPLICATION}, ALL_NODES).get(); + log( + INFO, + "app", + "INFO REPLICATION responses from all nodes are " + infoResponse.getMultiValue()); } /** @@ -125,7 +173,7 @@ private static void execAppLogic() throws ExecutionException { Collections.singletonList(NodeAddress.builder().host("localhost").port(6379).build()); while (true) { - try (GlideClient client = createClient(nodeList)) { + try (GlideClusterClient client = createClient(nodeList)) { appLogic(client); return; } catch (CancellationException e) { @@ -164,7 +212,7 @@ private static void execAppLogic() throws ExecutionException { } /** - * The entry point of the standalone example. This method sets up the logger configuration and + * The entry point of the cluster example. This method sets up the logger configuration and * executes the main application logic. * * @param args Command-line arguments passed to the application. diff --git a/examples/java/src/main/java/glide/examples/GlideJsonExample.java b/examples/java/src/main/java/glide/examples/GlideJsonExample.java index 2e21feea3e..d5060d3fc1 100644 --- a/examples/java/src/main/java/glide/examples/GlideJsonExample.java +++ b/examples/java/src/main/java/glide/examples/GlideJsonExample.java @@ -5,16 +5,18 @@ import static glide.api.logging.Logger.Level.INFO; import static glide.api.logging.Logger.Level.WARN; import static glide.api.logging.Logger.log; +import static glide.api.models.configuration.RequestRoutingConfiguration.SimpleMultiNodeRoute.ALL_NODES; -import glide.api.GlideClient; +import glide.api.GlideClusterClient; import glide.api.commands.servermodules.Json; import glide.api.logging.Logger; -import glide.api.models.configuration.GlideClientConfiguration; +import glide.api.models.ClusterValue; +import glide.api.models.commands.InfoOptions.Section; +import glide.api.models.configuration.GlideClusterClientConfiguration; import glide.api.models.configuration.NodeAddress; import glide.api.models.exceptions.ClosingException; import glide.api.models.exceptions.ConnectionException; import glide.api.models.exceptions.TimeoutException; - import java.util.Collections; import java.util.List; import java.util.concurrent.CancellationException; @@ -24,48 +26,57 @@ public class GlideJsonExample { /** - * Creates and returns a GlideClient instance. + * Creates and returns a GlideClusterClient instance. * - *

This function initializes a GlideClient with the provided list of nodes. The - * list may contain either only primary node or a mix of primary and replica nodes. The - * GlideClient - * use these nodes to connect to the Standalone setup servers. + *

This function initializes a GlideClusterClient with the provided list of nodes. + * The list may contain the address of one or more cluster nodes, and the client will + * automatically discover all nodes in the cluster. * - * @return A GlideClient connected to the provided node address. + * @return A GlideClusterClient connected to the discovered nodes. * @throws CancellationException if the operation is cancelled. * @throws ExecutionException if the client fails due to execution errors. * @throws InterruptedException if the operation is interrupted. */ - public static GlideClient createClient(List nodeList) + public static GlideClusterClient createClient(List nodeList) throws CancellationException, ExecutionException, InterruptedException { - // Check `GlideClientConfiguration` for additional options. - GlideClientConfiguration config = - GlideClientConfiguration.builder() + // Check `GlideClusterClientConfiguration` for additional options. + GlideClusterClientConfiguration config = + GlideClusterClientConfiguration.builder() .addresses(nodeList) // Enable this field if the servers are configured with TLS. // .useTLS(true); .build(); - GlideClient client = GlideClient.createClient(config).get(); + GlideClusterClient client = GlideClusterClient.createClient(config).get(); return client; } /** - * Executes the main logic of the application, performing basic operations such as JSON.SET and JSON.GET using the provided GlideClusterClient. + * Executes the main logic of the application, performing basic operations such as JSON.SET and + * JSON.GET using the provided GlideClusterClient. * * @param client An instance of GlideClusterClient. * @throws ExecutionException if an execution error occurs during operations. * @throws InterruptedException if the operation is interrupted. */ - public static void appLogic(GlideClusterClient client) throws ExecutionException, InterruptedException { - - // TODO: test example against memorydb instance + public static void appLogic(GlideClusterClient client) + throws ExecutionException, InterruptedException { + + CompletableFuture setResponse = Json.set(client, "key", "$", "{\"a\": 1.0,\"b\": 2}"); + System.out.println("The set response is " + setResponse.get()); // The response should be "OK" - CompletableFuture setResponse = Json.set(client, key, "$", "{\"a\": 1.0,\"b\": 2}"); - System.out.println("The set response is " + setResponse.get()); // The response should be "OK" + CompletableFuture getResponse = Json.get(client, "key", new String[] {"$.a", "$.b"}); + System.out.println( + "The get response is " + + getResponse.get()); // The response should be "{\"$.a\":[1.0],\"$.b\":[2]}" - CompletableFuture getResponse = Json.get(client, key, "$.a", "$.b"); - System.out.println("The get response is " + getResponse.get()); // The response should be "{\"$.a\":[1.0],\"$.b\":[2]}" + // Send INFO REPLICATION with routing option to all nodes + ClusterValue infoResponse = + client.info(new Section[] {Section.REPLICATION}, ALL_NODES).get(); + log( + INFO, + "app", + "INFO REPLICATION responses from all nodes are " + infoResponse.getMultiValue()); } /** @@ -80,7 +91,7 @@ private static void execAppLogic() throws ExecutionException { Collections.singletonList(NodeAddress.builder().host("localhost").port(6379).build()); while (true) { - try (GlideClient client = createClient(nodeList)) { + try (GlideClusterClient client = createClient(nodeList)) { appLogic(client); return; } catch (CancellationException e) { @@ -119,7 +130,7 @@ private static void execAppLogic() throws ExecutionException { } /** - * The entry point of the standalone example. This method sets up the logger configuration and + * The entry point of the cluster example. This method sets up the logger configuration and * executes the main application logic. * * @param args Command-line arguments passed to the application. From d0b0fd19657a2eb11e4b9b548e071a9b8fc3aad0 Mon Sep 17 00:00:00 2001 From: Chloe Date: Tue, 26 Nov 2024 21:19:36 +0000 Subject: [PATCH 4/9] changed OK Signed-off-by: Chloe --- examples/java/src/main/java/glide/examples/GlideFtExample.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/java/src/main/java/glide/examples/GlideFtExample.java b/examples/java/src/main/java/glide/examples/GlideFtExample.java index 125c4a998a..98d61849c3 100644 --- a/examples/java/src/main/java/glide/examples/GlideFtExample.java +++ b/examples/java/src/main/java/glide/examples/GlideFtExample.java @@ -77,7 +77,7 @@ public static void appLogic(GlideClusterClient client) FTCreateOptions.builder() .dataType(DataType.HASH) .prefixes(new String[] {prefix}) - .build()); // ok + .build()); // "OK" CompletableFuture hsetResponse = client.hset( From a1b8e95201a25712b9ccee72b4f4a54f07074729 Mon Sep 17 00:00:00 2001 From: Chloe Date: Thu, 28 Nov 2024 00:50:43 +0000 Subject: [PATCH 5/9] update vss for python Signed-off-by: Chloe --- examples/python/ft_example.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/examples/python/ft_example.py b/examples/python/ft_example.py index 500c09c646..1a54eac031 100644 --- a/examples/python/ft_example.py +++ b/examples/python/ft_example.py @@ -57,19 +57,29 @@ async def app_logic(client: GlideClusterClient): Args: client (GlideClusterClient): An instance of GlideClient. """ - - # TODO: test against memory db instance - # Create a vector - create_response = await ft.create(client, "index", + index = prefix + str(uuid.uuid4()) + create_response = await ft.create(client, index, schema=[ NumericField("$.a", "a"), NumericField("$.b", "b"), ], options=FtCreateOptions(DataType.JSON), ) - Logger.log(LogLevel.INFO, "app", f"Create response is = {create_response!r}") + Logger.log(LogLevel.INFO, "app", f"Create response is = {create_response!r}") # 'OK' + # Create a json key. + assert ( + await GlideJson.set(glide_client, json_key1, "$", json.dumps(json_value1)) + == OK + ) + assert ( + await GlideJson.set(glide_client, json_key2, "$", json.dumps(json_value2)) + == OK + ) + + time.sleep(self.sleep_wait_time) + # Search for the vector search_response = await ft.search(glide_client, index, "*", options=ft_search_options) ft_search_options = FtSearchOptions( From 71037e0c9f0f5d5b2e54d9dfd892e209c098e5dd Mon Sep 17 00:00:00 2001 From: Chloe Date: Thu, 28 Nov 2024 00:52:03 +0000 Subject: [PATCH 6/9] remove todo Signed-off-by: Chloe --- examples/python/json_example.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/python/json_example.py b/examples/python/json_example.py index 4c058ca04e..c46de4f25a 100644 --- a/examples/python/json_example.py +++ b/examples/python/json_example.py @@ -56,8 +56,6 @@ async def app_logic(client: TGlideClient): client (TGlideClient): An instance of GlideClient. """ - # TODO: test against memory db instance - json_value = {"a": 1.0, "b": 2} # Send SET and GET set_response = await json.set(client, "key", "$") From c2196353ee85aa5b67da8444ab4e01e86cad0900 Mon Sep 17 00:00:00 2001 From: Chloe Yip <168601573+cyip10@users.noreply.github.com> Date: Thu, 28 Nov 2024 14:24:28 -0800 Subject: [PATCH 7/9] Update ft_example.py Signed-off-by: Chloe Yip <168601573+cyip10@users.noreply.github.com> --- examples/python/ft_example.py | 68 ++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/examples/python/ft_example.py b/examples/python/ft_example.py index 1a54eac031..d5b4de89e0 100644 --- a/examples/python/ft_example.py +++ b/examples/python/ft_example.py @@ -1,53 +1,52 @@ import asyncio -from typing import List, Tuple +from typing import List, Tuple, Optional + +from glide.async_commands.server_modules import glide_json as json +from glide.async_commands.server_modules import ft from glide import ( + AllNodes, ClosingError, ConnectionError, - GlideClient, - GlideClientConfiguration, + GlideClusterClient, + GlideClusterClientConfiguration, + InfoSection, Logger, LogLevel, NodeAddress, RequestError, - TimeoutError + TimeoutError, ) -from python.glade.async_commands.server_modules import ft -from glide.async_commands.server_modules.ft_options.ft_search_options import ( - FtSearchOptions, -) async def create_client( - nodes_list: List[Tuple[str, int]] = [("localhost", 6379)] -) -> GlideClient: + nodes_list: Optional[List[Tuple[str, int]]] = None +) -> GlideClusterClient: """ - Creates and returns a GlideClient instance. + Creates and returns a GlideClusterClient instance. - This function initializes a GlideClient with the provided list of nodes. - The nodes_list may contain either only primary node or a mix of primary - and replica nodes. The GlideClient use these nodes to connect to - the Standalone setup servers. + This function initializes a GlideClusterClient with the provided list of nodes. + The nodes_list may contain the address of one or more cluster nodes, and the + client will automatically discover all nodes in the cluster. Args: nodes_list (List[Tuple[str, int]]): A list of tuples where each tuple contains a host (str) and port (int). Defaults to [("localhost", 6379)]. Returns: - GlideClient: An instance of GlideClient connected to the specified nodes. + GlideClusterClient: An instance of GlideClusterClient connected to the discovered nodes. """ - addresses = [] - for host, port in nodes_list: - addresses.append(NodeAddress(host, port)) - - # Check `GlideClientConfiguration` for additional options. - config = GlideClientConfiguration( - addresses, + if nodes_list is None: + nodes_list = [("localhost", 6379)] + addresses = [NodeAddress(host, port) for host, port in nodes_list] + # Check `GlideClusterClientConfiguration` for additional options. + config = GlideClusterClientConfiguration( + addresses=addresses, + client_name="test_cluster_client", # Enable this field if the servers are configured with TLS. # use_tls=True ) - return await GlideClient.create(config) - + return await GlideClusterClient.create(config) async def app_logic(client: GlideClusterClient): """ @@ -59,6 +58,10 @@ async def app_logic(client: GlideClusterClient): """ # Create a vector index = prefix + str(uuid.uuid4()) + json_key1 = prefix + "1" + json_key2 = prefix + "2" + json_value1 = {"a": 11111, "b": 2, "c": 3} + json_value2 = {"a": 22222, "b": 2, "c": 3} create_response = await ft.create(client, index, schema=[ NumericField("$.a", "a"), @@ -111,12 +114,13 @@ async def exec_app_logic(): "glide", f"Authentication error encountered: {e}", ) - raise e - Logger.log( - LogLevel.WARN, - "glide", - f"Client has closed and needs to be re-created: {e}", - ) + else: + Logger.log( + LogLevel.WARN, + "glide", + f"Client has closed and needs to be re-created: {e}", + ) + raise e except TimeoutError as e: # A request timed out. You may choose to retry the execution based on your application's logic Logger.log(LogLevel.ERROR, "glide", f"TimeoutError encountered: {e}") @@ -139,7 +143,7 @@ async def exec_app_logic(): Logger.log( LogLevel.WARN, "glide", - f"Encountered an error while closing the client: {e}", + f"Error encountered while closing the client: {e}", ) From 4aff7159cc630ac3e68a81420d77d2e6309ad2af Mon Sep 17 00:00:00 2001 From: Chloe Yip <168601573+cyip10@users.noreply.github.com> Date: Thu, 28 Nov 2024 14:25:03 -0800 Subject: [PATCH 8/9] Update json_example.py Signed-off-by: Chloe Yip <168601573+cyip10@users.noreply.github.com> --- examples/python/json_example.py | 72 +++++++++++++++++---------------- 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/examples/python/json_example.py b/examples/python/json_example.py index c46de4f25a..7a57d74671 100644 --- a/examples/python/json_example.py +++ b/examples/python/json_example.py @@ -1,68 +1,69 @@ import asyncio -from typing import List, Tuple +from typing import List, Tuple, Optional + +from glide.async_commands.server_modules import glide_json as json from glide import ( + AllNodes, ClosingError, ConnectionError, - GlideClient, - GlideClientConfiguration, + GlideClusterClient, + GlideClusterClientConfiguration, + InfoSection, Logger, LogLevel, NodeAddress, RequestError, - TimeoutError + TimeoutError, ) -from python.glade.async_commands.server_modules import glide_json - async def create_client( - nodes_list: List[Tuple[str, int]] = [("localhost", 6379)] -) -> GlideClient: + nodes_list: Optional[List[Tuple[str, int]]] = None +) -> GlideClusterClient: """ - Creates and returns a GlideClient instance. + Creates and returns a GlideClusterClient instance. - This function initializes a GlideClient with the provided list of nodes. - The nodes_list may contain either only primary node or a mix of primary - and replica nodes. The GlideClient use these nodes to connect to - the Standalone setup servers. + This function initializes a GlideClusterClient with the provided list of nodes. + The nodes_list may contain the address of one or more cluster nodes, and the + client will automatically discover all nodes in the cluster. Args: nodes_list (List[Tuple[str, int]]): A list of tuples where each tuple contains a host (str) and port (int). Defaults to [("localhost", 6379)]. Returns: - GlideClient: An instance of GlideClient connected to the specified nodes. + GlideClusterClient: An instance of GlideClusterClient connected to the discovered nodes. """ - addresses = [] - for host, port in nodes_list: - addresses.append(NodeAddress(host, port)) - - # Check `GlideClientConfiguration` for additional options. - config = GlideClientConfiguration( - addresses, + if nodes_list is None: + nodes_list = [("localhost", 6379)] + addresses = [NodeAddress(host, port) for host, port in nodes_list] + # Check `GlideClusterClientConfiguration` for additional options. + config = GlideClusterClientConfiguration( + addresses=addresses, + client_name="test_cluster_client", # Enable this field if the servers are configured with TLS. # use_tls=True ) - return await GlideClient.create(config) + return await GlideClusterClient.create(config) - -async def app_logic(client: TGlideClient): +async def app_logic(client: GlideClusterClient): """ Executes the main logic of the application, performing basic operations such as JSON.SET and JSON.GET using the provided GlideClient. Args: - client (TGlideClient): An instance of GlideClient. + client (GlideClusterClient): An instance of GlideClient. """ json_value = {"a": 1.0, "b": 2} + json_str = json.dumps(value) # Send SET and GET - set_response = await json.set(client, "key", "$") - Logger.log(LogLevel.INFO, "app", f"Set response is = {set_response!r}") + set_response = await json.set(client, "key", "$", json_str) + Logger.log(LogLevel.INFO, "app", f"Set response is = {set_response!r}") # 'OK' get_response = await json.get(client, "key", "$") - Logger.log(LogLevel.INFO, "app", f"Get response is = {get_response.decode()!r}") + Logger.log(LogLevel.INFO, "app", f"Get response is = {get_response.decode()!r}") # "[{\"a\":1.0,\"b\":2}]" async def exec_app_logic(): @@ -84,12 +85,13 @@ async def exec_app_logic(): "glide", f"Authentication error encountered: {e}", ) - raise e - Logger.log( - LogLevel.WARN, - "glide", - f"Client has closed and needs to be re-created: {e}", - ) + else: + Logger.log( + LogLevel.WARN, + "glide", + f"Client has closed and needs to be re-created: {e}", + ) + raise e except TimeoutError as e: # A request timed out. You may choose to retry the execution based on your application's logic Logger.log(LogLevel.ERROR, "glide", f"TimeoutError encountered: {e}") @@ -112,7 +114,7 @@ async def exec_app_logic(): Logger.log( LogLevel.WARN, "glide", - f"Encountered an error while closing the client: {e}", + f"Error encountered while closing the client: {e}", ) From 66b7623226792ed0be8bdeb009d6fa7df4aaf826 Mon Sep 17 00:00:00 2001 From: Chloe Date: Fri, 29 Nov 2024 18:17:33 +0000 Subject: [PATCH 9/9] address comment Signed-off-by: Chloe --- .../java/glide/examples/GlideFtExample.java | 45 +++++++++---------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/examples/java/src/main/java/glide/examples/GlideFtExample.java b/examples/java/src/main/java/glide/examples/GlideFtExample.java index 98d61849c3..4649711085 100644 --- a/examples/java/src/main/java/glide/examples/GlideFtExample.java +++ b/examples/java/src/main/java/glide/examples/GlideFtExample.java @@ -5,12 +5,19 @@ import static glide.api.logging.Logger.Level.INFO; import static glide.api.logging.Logger.Level.WARN; import static glide.api.logging.Logger.log; +import static glide.api.models.GlideString.gs; import static glide.api.models.configuration.RequestRoutingConfiguration.SimpleMultiNodeRoute.ALL_NODES; import glide.api.GlideClusterClient; import glide.api.commands.servermodules.FT; import glide.api.logging.Logger; import glide.api.models.ClusterValue; +import glide.api.models.commands.FT.FTCreateOptions; +import glide.api.models.commands.FT.FTCreateOptions.DataType; +import glide.api.models.commands.FT.FTCreateOptions.DistanceMetric; +import glide.api.models.commands.FT.FTCreateOptions.FieldInfo; +import glide.api.models.commands.FT.FTCreateOptions.VectorFieldHnsw; +import glide.api.models.commands.FT.FTSearchOptions; import glide.api.models.commands.InfoOptions.Section; import glide.api.models.configuration.GlideClusterClientConfiguration; import glide.api.models.configuration.NodeAddress; @@ -27,6 +34,9 @@ public class GlideFtExample { + /** Waiting interval to let server process the data before querying */ + private static final int DATA_PROCESSING_TIMEOUT = 1000; // ms + /** * Creates and returns a GlideClusterClient instance. * @@ -86,7 +96,7 @@ public static void appLogic(GlideClusterClient client) gs("vec"), gs( new byte[] { - (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0 + 0, 0, 0, 0, 0, 0, 0, 0 }))); // response is 1L which represents the number of fields that were added. hsetResponse = @@ -96,33 +106,20 @@ public static void appLogic(GlideClusterClient client) gs("vec"), gs( new byte[] { - (byte) 0, - (byte) 0, - (byte) 0, - (byte) 0, - (byte) 0, - (byte) 0, - (byte) 0x80, - (byte) 0xBF + 0, 0, 0, 0, 0, 0, (byte) 0x80, (byte) 0xBF }))); // response is 1L which represents the number of fields that were added. Thread.sleep(DATA_PROCESSING_TIMEOUT); // let server digest the data and update // These are the optional arguments used for the FT.search command var options = FTSearchOptions.builder() - .params( - Map.of( - gs("query_vec"), - gs( - new byte[] { - (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, - (byte) 0 - }))) + .params(Map.of(gs("query_vec"), gs(new byte[] {0, 0, 0, 0, 0, 0, 0, 0}))) .build(); String query = "*=>[KNN 2 @VEC $query_vec]"; // This is the text query to search for CompletableFuture searchResponse = FT.search(client, index, query, options); - // When you call .get() on searchResponse, the result will be an Object[] as shown in the commented assert test below. + // When you call .get() on searchResponse, the result will be an Object[] as shown in the + // commented assert test below. // assertArrayEquals( // new Object[] { // 2L, @@ -136,12 +133,12 @@ public static void appLogic(GlideClusterClient client) // gs("vec"), // gs( // new byte[] { - // (byte) 0, - // (byte) 0, - // (byte) 0, - // (byte) 0, - // (byte) 0, - // (byte) 0, + // 0, + // 0, + // 0, + // 0, + // 0, + // 0, // (byte) 0x80, // (byte) 0xBF // })))