diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc index 56c109be2..2df495881 100644 --- a/docs/modules/ROOT/nav.adoc +++ b/docs/modules/ROOT/nav.adoc @@ -1,5 +1,5 @@ .Get started -* xref:whats-new.adoc[What's new in 5.4] +* xref:whats-new.adoc[What's new] * xref:what-is-hazelcast.adoc[What is Hazelcast Platform] * xref:getting-started:editions.adoc[Available versions] //* xref:placeholder.adoc[Feature overview] @@ -41,7 +41,7 @@ ** xref:migrate:upgrading-from-imdg-3.adoc[] ** xref:migrate:migration-tool-imdg.adoc[] *** xref:migrate:dmt-command-reference.adoc[] -* xref:release-notes:releases.adoc[Release notes] +//* xref:release-notes:releases.adoc[Release notes] // * xref:placeholder.adoc[Troubleshooting] // * xref:placeholder.adoc[FAQ] diff --git a/docs/modules/ROOT/pages/whats-new.adoc b/docs/modules/ROOT/pages/whats-new.adoc index 6af05b347..8521e76ca 100644 --- a/docs/modules/ROOT/pages/whats-new.adoc +++ b/docs/modules/ROOT/pages/whats-new.adoc @@ -1,7 +1,9 @@ = What's New in Hazelcast Platform -:description: Here are the highlights of what's new and improved in Hazelcast Platform +:description: Here are the highlights of what's new and improved in Hazelcast Platform 5.4. [[whats-new]] +NOTE: The What's New page for Hazelcast Platform 5.5 will be available when this version is released. For the last major release, see below. + {description} == Use CP Map for mission-critical workflows diff --git a/docs/modules/tutorials/pages/cpp-client-getting-started.adoc b/docs/modules/tutorials/pages/cpp-client-getting-started.adoc deleted file mode 100644 index 62abe0062..000000000 --- a/docs/modules/tutorials/pages/cpp-client-getting-started.adoc +++ /dev/null @@ -1,412 +0,0 @@ -= Getting Started with the Hazelcast C++ Client -:description: This tutorial will get you started with the Hazelcast C++ client and manipulate a map. - -== What You'll Learn - -{description} - -== Before you Begin - -* C++ 11 or above -* https://hazelcast.com/products/viridian/[Hazelcast Viridian Cloud Account] -* A text editor or IDE - -== Start a Hazelcast Viridian Cloud Cluster - -1. Sign up for a Hazelcast Viridian Cloud account (free trial is available). -2. Log in to your Hazelcast Viridian Cloud account and start your trial by filling in the welcome questionnaire. -3. A Viridian cluster will be created automatically when you start your trial. -4. Press the Connect Cluster dialog and switch over to the Advanced setup tab for connection information needed below. -5. From the Advanced setup tab, download the keystore files and take note of your Cluster ID, Discovery Token and Password as you will need them later. - -== Setup a Hazelcast Client - -Create a new folder and navigate to it: - -[source] ----- -mkdir hazelcast-cpp-example -cd hazelcast-cpp-example ----- - -Download and install Vcpkg: + - -for Windows; -[source,bash] ----- -git clone https://github.com/microsoft/vcpkg -.\vcpkg\bootstrap-vcpkg.bat ----- - -for non-Windows; -[source,bash] ----- -git clone https://github.com/microsoft/vcpkg -./vcpkg/bootstrap-vcpkg.sh ----- - -Download and install hazelcast-cpp-client: + - -for Windows; -[source,bash] ----- -.\vcpkg\vcpkg.exe install "hazelcast-cpp-client[openssl]" --recurse ----- - -for non-Windows; -[source,bash] ----- -./vcpkg/vcpkg install "hazelcast-cpp-client[openssl]" --recurse ----- - -NOTE: Avoid directory names in your path that contain spaces or other non-standard characters. - -Extract the keystore files you downloaded from Viridian into this directory. The files you need for this tutorial are: - -[source,bash] ----- -ca.pem -cert.pem -key.pem ----- - -Create a CMake file in this directory, named "CMakeLists.txt" as follows: - -[source,bash] ----- -cmake_minimum_required(VERSION 3.10) - -project(HazelcastCloud) - -set(CMAKE_CXX_STANDARD 11) -set(CMAKE_CXX_STANDARD_REQUIRED ON) - -find_package(hazelcast-cpp-client CONFIG REQUIRED) - -if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/example.cpp) - add_executable(example example.cpp) - target_link_libraries(example PRIVATE hazelcast-cpp-client::hazelcast-cpp-client) -endif() ----- - -You should have the following entries in the directory: -[source,bash] ----- -CMakeLists.txt -ca.pem -cert.pem -key.pem -vcpkg ----- - -== Understanding the C++ Client - -The following section creates and starts a Hazelcast client with default configuration, connects to your Viridian cluster before shutting the client down at the end. - -Create a C++ file named “example.cpp” and put the following code inside it: - -[source,cpp] ----- -#include -#include - -int -main(int argc, char** argv) -{ - hazelcast::client::client_config config; - - // Viridian Cluster Name and Token - config.set_cluster_name(""); - auto& cloud_configuration = config.get_network_config().get_cloud_config(); - cloud_configuration.enabled = true; - cloud_configuration.discovery_token = ""; - - // configure SSL - boost::asio::ssl::context ctx(boost::asio::ssl::context::tlsv12); - - try { - ctx.load_verify_file("ca.pem"); - ctx.use_certificate_file("cert.pem", boost::asio::ssl::context::pem); - ctx.set_password_callback( - [&](std::size_t max_length, - boost::asio::ssl::context::password_purpose purpose) { - return ""; - }); - ctx.use_private_key_file("key.pem", boost::asio::ssl::context::pem); - } catch (std::exception& e) { - std::cerr << "You should copy ca.pem, cert.pem and key.pem files to " - "the working directory, exception cause " - << e.what() << std::endl; - exit(EXIT_FAILURE); - } - config.get_network_config().get_ssl_config().set_context(std::move(ctx)); - - // Connect to your Hazelcast Cluster - auto client = hazelcast::new_client(std::move(config)).get(); - - // take actions - std::cout << "Welcome to your Hazelcast Viridian Cluster!" << std::endl; - - // Shutdown the client connection - client.shutdown().get(); -} ----- - -Compile using CMake as follows: - -[source,bash] ----- -cmake -B build -S . -DCMAKE_TOOLCHAIN_FILE=./vcpkg/scripts/buildsystems/vcpkg.cmake -cmake --build build ----- - -Once complete, run the example: - -[source,bash] ----- -./build/example ----- - -For more information about Vcpkg installation check https://github.com/hazelcast/hazelcast-cpp-client/blob/master/Reference_Manual.md#112-vcpkg-users[here]. -In this tutorial we use CMake for compilation, for other options you can check https://github.com/hazelcast/hazelcast-cpp-client/blob/master/Reference_Manual.md#13-compiling-your-project[here]. - -To understand and use the client, review the https://hazelcast.github.io/hazelcast-cpp-client/api-index.html[C++ API documentation] to better understand what is possible. - -== Understanding the Hazelcast SQL API - -Hazelcast SQL API is a Calcite SQL based interface to allow you to interact with Hazelcast much like any other datastore. - -In the following example, we will create a map and insert into it, entries where the keys are ids and the values are defined as an object representing a city. - -[source,cpp] ----- -#include -#include - -void -create_mapping(hazelcast::client::hazelcast_client client); -void -insert_cities(hazelcast::client::hazelcast_client client); -void -fetch_cities(hazelcast::client::hazelcast_client client); - -struct CityDTO -{ - std::string cityName; - std::string country; - int population; -}; - -// CityDTO serializer -namespace hazelcast { -namespace client { -namespace serialization { - -template<> -struct hz_serializer : compact::compact_serializer -{ - static void write(const CityDTO& object, compact::compact_writer& out) - { - out.write_int32("population", object.population); - out.write_string("city", object.cityName); - out.write_string("country", object.country); - } - - static CityDTO read(compact::compact_reader& in) - { - CityDTO c; - - c.population = in.read_int32("population"); - boost::optional city = in.read_string("city"); - - if (city) { - c.cityName = *city; - } - - boost::optional country = in.read_string("country"); - - if (country) { - c.country = *country; - } - - return c; - } - - static std::string type_name() { return "CityDTO"; } -}; - -} // namespace serialization -} // namespace client -} // namespace hazelcast - -int -main(int argc, char** argv) -{ - hazelcast::client::client_config config; - - // Viridian Cluster Name and Token - config.set_cluster_name(""); - auto& cloud_configuration = config.get_network_config().get_cloud_config(); - cloud_configuration.enabled = true; - cloud_configuration.discovery_token = ""; - - // configure SSL - boost::asio::ssl::context ctx(boost::asio::ssl::context::tlsv12); - - try { - ctx.load_verify_file("ca.pem"); - ctx.use_certificate_file("cert.pem", boost::asio::ssl::context::pem); - ctx.set_password_callback( - [&](std::size_t max_length, - boost::asio::ssl::context::password_purpose purpose) { - return ""; - }); - ctx.use_private_key_file("key.pem", boost::asio::ssl::context::pem); - } catch (std::exception& e) { - std::cerr << "You should copy ca.pem, cert.pem and key.pem files to " - "the working directory, exception cause " - << e.what() << std::endl; - exit(EXIT_FAILURE); - } - config.get_network_config().get_ssl_config().set_context(std::move(ctx)); - - // Connect to your Hazelcast Cluster - auto client = hazelcast::new_client(std::move(config)).get(); - - // take actions - create_mapping(client); - insert_cities(client); - fetch_cities(client); - - // Shutdown the client connection - client.shutdown().get(); -} - -void -create_mapping(hazelcast::client::hazelcast_client client) -{ - // Mapping is required for your distributed map to be queried over SQL. - // See: https://docs.hazelcast.com/hazelcast/latest/sql/mapping-to-maps - - std::cout << "Creating the mapping..."; - - auto sql = client.get_sql(); - - auto result = sql - .execute(R"(CREATE OR REPLACE MAPPING - cities ( - __key INT, - country VARCHAR, - city VARCHAR, - population INT) TYPE IMAP - OPTIONS ( - 'keyFormat' = 'int', - 'valueFormat' = 'compact', - 'valueCompactTypeName' = 'CityDTO'))") - .get(); - - std::cout << "OK." << std::endl; -} - -void -insert_cities(hazelcast::client::hazelcast_client client) -{ - auto sql = client.get_sql(); - - try { - sql.execute("DELETE FROM cities").get(); - - std::cout << "Inserting data..."; - - // Create mapping for the integers. This needs to be done only once per - // map. - auto result = sql - .execute(R"(INSERT INTO cities - (__key, city, country, population) VALUES - (1, 'London', 'United Kingdom', 9540576), - (2, 'Manchester', 'United Kingdom', 2770434), - (3, 'New York', 'United States', 19223191), - (4, 'Los Angeles', 'United States', 3985520), - (5, 'Istanbul', 'Türkiye', 15636243), - (6, 'Ankara', 'Türkiye', 5309690), - (7, 'Sao Paulo ', 'Brazil', 22429800))") - .get(); - - std::cout << "OK." << std::endl; - } catch (hazelcast::client::exception::iexception& e) { - // don't panic for duplicated keys. - std::cerr << "FAILED, duplicated keys " << e.what() << std::endl; - } -} - -void -fetch_cities(hazelcast::client::hazelcast_client client) -{ - std::cout << "Fetching cities..."; - - auto result = - client.get_sql().execute("SELECT __key, this FROM cities").get(); - - std::cout << "OK." << std::endl; - std::cout << "--Results of 'SELECT __key, this FROM cities'" << std::endl; - - std::printf("| %-4s | %-20s | %-20s | %-15s |\n", - "id", - "country", - "city", - "population"); - - for (auto itr = result->iterator(); itr.has_next();) { - auto page = itr.next().get(); - - for (auto const& row : page->rows()) { - - auto id = row.get_object("__key"); - auto city = row.get_object("this"); - std::printf("| %-4d | %-20s | %-20s | %-15d |\n", - *id, - city->country.c_str(), - city->cityName.c_str(), - city->population); - } - } - - std::cout - << "\n!! Hint !! You can execute your SQL queries on your Viridian " - "cluster over the management center. \n 1. Go to 'Management Center' " - "of your Hazelcast Viridian cluster. \n 2. Open the 'SQL Browser'. \n " - "3. Try to execute 'SELECT * FROM cities'.\n"; -} ----- - -The output of this code is given below: - -[source,bash] ----- -Creating the mapping...OK. -Inserting data...OK. -Fetching cities...OK. ---Results of 'SELECT __key, this FROM cities' -| id | country | city | population | -| 2 | United Kingdom | Manchester | 2770434 | -| 6 | Turkiye | Ankara | 5309690 | -| 1 | United Kingdom | London | 9540576 | -| 7 | Brazil | Sao Paulo | 22429800 | -| 4 | United States | Los Angeles | 3985520 | -| 5 | Turkiye | Istanbul | 15636243 | -| 3 | United States | New York | 19223191 | ----- - -NOTE: Ordering of the keys is NOT enforced and results may NOT correspond to insertion order. - -== Summary - -In this tutorial, you learned how to get started with the Hazelcast C++ Client, connect to a Viridian instance and put data into a distributed map. - -== See Also - -There are a lot of things that you can do with the C++ Client. For more, such as how you can query a map with predicates and SQL, -check out our https://github.com/hazelcast/hazelcast-cpp-client[C++ Client repository] and our https://hazelcast.github.io/hazelcast-cpp-client/api-index.html[C++ API documentation] to better understand what is possible. - -If you have any questions, suggestions, or feedback please do not hesitate to reach out to us via https://slack.hazelcast.com/[Hazelcast Community Slack]. -Also, please take a look at https://github.com/hazelcast/hazelcast-cpp-client/issues[the issue list] if you would like to contribute to the client. diff --git a/docs/modules/tutorials/pages/cpsubsystem.adoc b/docs/modules/tutorials/pages/cpsubsystem.adoc deleted file mode 100644 index a2ef13e93..000000000 --- a/docs/modules/tutorials/pages/cpsubsystem.adoc +++ /dev/null @@ -1,238 +0,0 @@ -= CP Subsystem and CPMap Tutorial -:description: In this tutorial, you will examine the operations of a CP-enabled Hazelcast Platform cluster, then work with the CPMap data structure using the Hazelcast CLC. - -{description} - -// Give some context about the use case for this tutorial. What will the reader learn? -== Context - -The Hazelcast CP Subsystem adds the capability of true consistency to the primarily AP Hazelcast Platform. When the CP Subsystem is enabled, application developers have access to CPMap, a key-value store similar in function to IMap that provides consistency guarantees. The CP Subsystem also supports Java concurrency primitives, guaranteeing atomic operations of these data structures. - -// Optional: What does the reader need before starting this tutorial? Think about tools or knowledge. Delete this section if your readers can dive straight into the lesson without requiring any prerequisite knowledge. -== Before you Begin - -Before starting this tutorial, make sure that you have installed the following: - -* https://www.docker.com/[Docker] -* https://docs.hazelcast.com/clc/latest/overview[Hazelcast Command Line Client (CLC)] -* https://www.oracle.com/java/technologies/downloads/[JDK 17 or later] -* https://www.docker.com/products/docker-desktop/[Docker Desktop] - -Optional - -* https://maven.apache.org/[Maven] - -* Your preferred Java IDE - -== Step 1. Set up the Cluster and Verify Operations - -In this section, you'll launch a Hazelcast cluster and Management Center using Docker. You'll verify that the CP Subsystem is up and ready for data. You'll then pause, then restart a cluster member and observe the changes in Management Center and view the system logs. - -. Download the repository from https://github.com/hazelcast-guides/cpsubsystem[GitHub]. - -. Run the following commands to start a Hazelcast cluster -+ -```cli -docker compose up -d -docker compose ps -``` -You should see four services up and running: three instances of Hazelcast, and one instance of Management Center. - -. Open the file `hazelcast.yaml` to review the cluster member configuration. - -. Open a web browser and connect to *localhost:8080*. This will open Management Center. Select Dev Mode to open the main dashboard. Go to *Settings*, then open *License*. Paste in the license key from `hazelcast.yaml`. Verify that the license includes Advanced CP, which is required for CPMap functionality. -+ -image::licensed_features.png[] - -. Close the settings screen. The main dashboard should show that the CP Subsystem is accessible. -+ -image::mc_main_dashboard.png[] - -. Scroll down to verify that the cluster has a total of three nodes. - -. From the left side menu, go to *CP Subsystem > Dashboard*. Note that the CP Subsystem has three nodes in the CP Stats window. Under CP Groups, the only group that exists is METADATA; this group is used for CP Subsystem management. - - -== Step 2. Create a CPMap Using CLC - -In this step, you'll use the CLC to connect to one of the cluster members. You'll create a CPMap and add data to the map. You'll then retrieve data from the map. - -. Open a separate terminal window. Enable CPMap capabilities in CLC (only needed for CLC 5.3.7). -+ -```cli -export CLC_EXPERIMENTAL_CPMAP=1 -``` - -. Start CLC using the provided configuration file. -+ -```cli -clc -c clc_docker.yaml -``` -. At the SQL prompt, use the `cpmap` commands to create a CPMap and add data, then retrieve the data. -+ -```cli -\cpmap -n trektos set 1 "James Kirk" -\cpmap -n trektos get 1 -``` -+ -[NOTE] -The backslash is needed for all CLC commands. Otherwise CLC assumes you are entering SQL commands. Type `\help` for a list of all available commands. - -. Run the `trektos.clc` script to add data to the CPMap. -+ -```cli -\script run trektos.clc -``` - -. Verify that additional entries have been added to the map. -+ -```cli -\cpmap -n trektos get 6 -``` - -. In Management Center, examine the CP Subsystem dashboard. Note that there is now a "default" group. This is the group maintaining the RAFT algorithm for the `trektos` CPMap. - -. In Management Center, select CPMaps from the left side. The screen lists the CPMap you just created, along with map statistics. - -. (Optional) In the Client subdirectory, we've included a sample Java client that creates an additional CPMap. To run the client, change to the Client subdirectory, then run the following Maven commands. -+ -```cli -mvn clean compile exec:java -Dexec.mainClass="Client4CP" -``` -+ -Use CLC and Management Center to verify the creation of a second CPMap. - -== Step 3. Simulating a Network Partition - -In this section, you will pause and restart individual cluster members to simulate network partition and member failure conditions. You'll learn about when the CP Subsystem can heal itself, and when administrator intervention is required. - -. From the CLC, run the script sw.clc. This creates an IMap. We will use this to compare data accessibility between an AP IMap and a CP CPMap. -+ -```cli -\script run sw.clc -``` - -. Retrieve an entry from the IMap. -+ -```cli -\map -n starwars get 1 -``` - -. In the terminal window, stop cluster member 2. Observe the changes in the CP Subsystem dashboard. -+ -```cli -docker stop cpsubsystem-hz2-1 -``` -+ -image::dashboard_paused_member.png[] - -. Review the log entries of one of the remaining members to see messages related to data migration for AP data and group rebalancing for CP data. The command is `docker logs `. -+ -Example output: -+ -image::member_depart_log.png[] - -. Using CLC, verify that you can still access both IMap and CPMap data. -+ -```cli -\map -n starwars get 1 -\cpmap -n trektos get 1 -``` - -. Stop cluster member 3. Note the changes in Management Center. -+ -``` -docker stop cpsubsystem-hz3-1 -``` - -. Verify that you can still access AP data, but cannot access CP data. Accessing CP data will give you a "Connecting to cluster..." message. - -. Start cluster member 2 -+ -```cli -docker start cpsubsystem-hz2-1 -``` -+ - -[NOTE] -At this point, we have created a situation where the CP Subsystem is unrecoverable. There is only a minority left in the group, and there is no majority "out there" that retains any CP data. The only path to recovery is to restart all the cluster members. The lesson here is to configure resilience into your CP Subsystem so this cannot happen! - -. Use Docker compose to remove all your containers. -+ -```cli -docker compose down -``` - -== Step 4: Configuring Resilience (Optional) - -In this step, we will add another cluster member, and configure the cluster for automatic member failure. - -. Open the file compose.yaml. Add a fourth instance of Hazelcast to the file. Save your changes. -+ -```cli - hz4: - image: hazelcast/hazelcast-enterprise:5.4.0 - environment: - JAVA_OPTS: -Dhazelcast.config=/project/hazelcast.yaml - volumes: - - ".:/project" -``` -. Open the file hazelcast.yaml. Modify the configuration as follows: -.. Set the member count to 4 -.. Add the timeout and set it to 60 seconds -.. Add the auto-removal and set it to 60 seconds -+ -```cli - cp-subsystem: - cp-member-count: 3 - group-size: 3 - session-time-to-live-seconds: 60 - missing-cp-member-auto-removal-seconds: 60 -``` - -. Start up the containers. -```cli -docker compose up -d -``` -. In Management Center, go to the CP Subsystem dashboard. You should now see four members listed. Note that one has zero nodes. This means it is not participating in any groups. -+ -image::4members.png[] - -. Check the IP address of hz4. If it is one of the active CP members, stop it. If it is not, then stop hz3. Observe the changes in Management System over the next few minutes. -+ -```cli -docker container inspect cpsubsystem-hz4-1 | grep "IPAddress" -docker stop cpsubsystem-hz4-1 -``` - -. Note that the node that previously was not participating in groups has been promoted and is now partipating in the group. -+ -image::promoted.png[] - -. Restart the stopped container. There will be no changes in Management Center, nor to the CP Subsystem. If you look at the log for the restarted system, you will see the following message. - -`2024-04-16 16:25:43 2024-04-16 23:25:43,655 [ INFO] [hz.recursing_benz.generic-operation.thread-3] [c.h.c.i.MetadataRaftGroupManager]: [172.19.0.3]:5701 [dev] [5.4.0] Disabling discovery of initial CP members since it is already completed...` - -. To bring the CP Subsystem back to all four members, use the Management Center dashboard to promote the restarted member. - -[NOTE] -Because we only have one group, no group rebalancing will occur. You can verify this by looking at the system logs for each member. - -== What's Next? - -You now have a working CP Subsystem setup. Experiment with creating multiple groups to observe group distribution when there are more subsystem members than needed by each group. Work with other CP data structures. The documentation links below will provide additional information on - - -== Summary - -In this tutorial, you worked with the CPMap data structure, and experimented with CP Subsystem management. - - -== See Also - -// Optionally, add some links to resources, such as other related guides. - -* Hazelcast Training: https://training.hazelcast.com/cp-subsystem[Strong Data Consistency] - this course provides instruction on CP subsystem operations, configuration, data structures, and fenced locks. -* https://docs.hazelcast.com/hazelcast/latest/cp-subsystem/cp-subsystem[CP Subsystem Overview] -* https://docs.hazelcast.com/hazelcast/latest/data-structures/cpmap[CPMap Documentation] -* https://docs.hazelcast.com/hazelcast/latest/cp-subsystem/cp-subsystem#persistence[CP Subsystem Persistence] diff --git a/docs/modules/tutorials/pages/csharp-client-getting-started.adoc b/docs/modules/tutorials/pages/csharp-client-getting-started.adoc deleted file mode 100644 index 199a37f40..000000000 --- a/docs/modules/tutorials/pages/csharp-client-getting-started.adoc +++ /dev/null @@ -1,389 +0,0 @@ -= Getting Started with the Hazelcast .NET Client -:description: In this tutorial you will see how to connect with the Hazelcast .NET client and manipulate a map. - -== What You'll Learn - -{description} - -== Before you Begin - -* .NET SDK 6.0 or above -* https://hazelcast.com/products/viridian/[Hazelcast Viridian Cloud Account] -* An IDE - -== Start a Hazelcast Viridian Cloud Cluster - -1. Sign up for a Hazelcast Viridian Cloud account (free trial is available). -2. Log in to your Hazelcast Viridian Cloud account and start your trial by filling in the welcome questionnaire. -3. A Viridian cluster will be created automatically when you start your trial. -4. Press the Connect Cluster dialog and switch over to the Advanced setup tab for connection information needed below. -5. From the Advanced setup tab, download the keystore files and take note of your Cluster ID, Discovery Token and Password as you will need them later. - -== Setup a Hazelcast Client - -Create a new folder and navigate to it: - -[source] ----- -mkdir hazelcast-csharp-example -cd hazelcast-csharp-example ----- - -Create a new .NET Console project using the commandline tool: - -[source] ----- -dotnet new console ----- - -Add the Hazelcast.NET Client as a dependency: - -[source] ----- -dotnet add Hazelcast.Net ----- - -Extract the keystore files you downloaded from Viridian into this directory. The files you need for this tutorial are: - -[source,bash] ----- -client.pfx ----- - -To understand and use the client, review the https://hazelcast.github.io/hazelcast-csharp-client/versions.html[.NET API documentation] to better understand what is possible. - -== Understanding the .NET Client - -The following section creates and starts a Hazelcast client with default configuration, connects to your Viridian cluster before shutting the client down at the end. - -Create a C# file named “Program.cs” and put the following code inside it: - -[source,cs] ----- -using Hazelcast; - -using System; - -namespace Client -{ - internal static class Program - { - public static async Task Main(string[] args) - { - // Create a client connection - var options = new HazelcastOptionsBuilder() - .With(config => - { - // Your Viridian cluster name. - config.ClusterName = ""; - - // Your discovery token to connect Viridian cluster. - config.Networking.Cloud.DiscoveryToken = ""; - - // Configure SSL. - config.Networking.Ssl.Enabled = true; - config.Networking.Ssl.ValidateCertificateChain = false; - config.Networking.Ssl.CertificatePath = "client.pfx"; - config.Networking.Ssl.CertificatePassword = ""; - }) - .With(args) // Pass command line args to the client - .Build(); - - await using var client = await HazelcastClientFactory.StartNewClientAsync(options); - - // take actions - } -} ----- - -== Understanding the Hazelcast SQL API - -Hazelcast SQL API is a Calcite SQL based interface to allow you to interact with Hazelcast much like any other datastore. - -In the following example, we will create a map and insert into it, entries where the keys are ids and the values are defined as an object representing a city. - -[source,cs] ----- -using Hazelcast; -using Hazelcast.Serialization.Compact; - -namespace Client -{ - internal class CityDTO - { - public string City { get; set; } - public string Country { get; set; } - public int Population { get; set; } - } - - internal class CitySerializer : ICompactSerializer - { - public string TypeName => "CityDTO"; - - public CityDTO Read(ICompactReader reader) - { - return new CityDTO() - { - City = reader.ReadString("city"), - Country = reader.ReadString("country"), - Population = reader.ReadInt32("population") - }; - } - - public void Write(ICompactWriter writer, CityDTO value) - { - writer.WriteString("city", value.City); - writer.WriteString("country", value.Country); - writer.WriteInt32("population", value.Population); - } - } - - internal static class Program - { - public static async Task Main(string[] args) - { - // Create a client connection - var options = new HazelcastOptionsBuilder() - .With(config => - { - // Your Viridian cluster name. - config.ClusterName = ""; - - // Your discovery token to connect Viridian cluster. - config.Networking.Cloud.DiscoveryToken = ""; - - // Configure SSL. - config.Networking.Ssl.Enabled = true; - config.Networking.Ssl.ValidateCertificateChain = false; - config.Networking.Ssl.CertificatePath = "client.pfx"; - config.Networking.Ssl.CertificatePassword = ""; - - // Register Compact serializer of City class. - config.Serialization.Compact.AddSerializer(new CitySerializer()); - }) - .With(args) // Pass command line args to the client - .Build(); - - // Connect to your Hazelcast Cluster - await using var client = await HazelcastClientFactory.StartNewClientAsync(options); - - // Create a map on the cluster - await CreateMapping(client); - - // Add some data - await PopulateCities(client); - - // Output the data - await FetchCities(client); - } - - private static async Task CreateMapping(IHazelcastClient client) - { - // Mapping is required for your distributed map to be queried over SQL. - // See: https://docs.hazelcast.com/hazelcast/latest/sql/mapping-to-maps - - Console.Write("\nCreating the mapping..."); - - var mappingCommand = @"CREATE OR REPLACE MAPPING - cities ( - __key INT, - country VARCHAR, - city VARCHAR, - population INT) TYPE IMAP - OPTIONS ( - 'keyFormat' = 'int', - 'valueFormat' = 'compact', - 'valueCompactTypeName' = 'CityDTO')"; - - await client.Sql.ExecuteCommandAsync(mappingCommand); - - Console.Write("OK."); - } - - private static async Task PopulateCities(IHazelcastClient client) - { - var deleteQuery = @"DELETE FROM cities"; - - var insertQuery = @"INSERT INTO cities - (__key, city, country, population) VALUES - (1, 'London', 'United Kingdom', 9540576), - (2, 'Manchester', 'United Kingdom', 2770434), - (3, 'New York', 'United States', 19223191), - (4, 'Los Angeles', 'United States', 3985520), - (5, 'Istanbul', 'Türkiye', 15636243), - (6, 'Ankara', 'Türkiye', 5309690), - (7, 'Sao Paulo ', 'Brazil', 22429800)"; - - try - { - Console.Write("\nInserting data..."); - await client.Sql.ExecuteCommandAsync(deleteQuery); - await client.Sql.ExecuteCommandAsync(insertQuery); - } - catch (Exception ex) - { - Console.WriteLine("FAILED. "+ex.ToString()); - } - - Console.Write("OK."); - } - - private static async Task FetchCities(IHazelcastClient client) - { - Console.Write("\nFetching cities..."); - - await using var result = await client.Sql.ExecuteQueryAsync("SELECT __key, this FROM cities"); - Console.Write("OK."); - Console.WriteLine("\n--Results of 'SELECT __key, this FROM cities'"); - Console.WriteLine(String.Format("| {0,4} | {1,20} | {2,20} | {3,15} |","id", "country", "city", "population")); - - await foreach (var row in result) - { - var id = row.GetKey(); // Corresponds to '__key' - var c = row.GetValue(); // Corresponds to 'this' - - Console.WriteLine(string.Format("| {0,4} | {1,20} | {2,20} | {3,15} |", - id, - c.Country, - c.City, - c.Population)); - } - } - } -} ----- - -The output of this code is given below: - -[source,bash] ----- -Creating the mapping...OK. -Inserting data...OK. -Fetching cities...OK. ---Results of 'SELECT __key, this FROM cities' -| id | country | city | population | -| 2 | United Kingdom | Manchester | 2770434 | -| 6 | Türkiye | Ankara | 5309690 | -| 1 | United Kingdom | London | 9540576 | -| 7 | Brazil | Sao Paulo | 22429800 | -| 4 | United States | Los Angeles | 3985520 | -| 5 | Türkiye | Istanbul | 15636243 | -| 3 | United States | New York | 19223191 | ----- - -NOTE: Ordering of the keys is NOT enforced and results may NOT correspond to insertion order. - -== Understanding the Hazelcast Map API - -A Hazelcast Map is a distributed key-value store, similar to C# dictionary. You can store key-value pairs in a Hazelcast Map. - -In the following example, we will work with map entries where the keys are ids and the values are defined as an object representing a city. - -[source,cs] ----- -using Hazelcast; - -namespace Client -{ - internal static class Program - { - public static async Task Main(string[] args) - { - // Create a client connection - var options = new HazelcastOptionsBuilder() - .With(config => - { - // Your Viridian cluster name. - config.ClusterName = ""; - - // Your discovery token to connect Viridian cluster. - config.Networking.Cloud.DiscoveryToken = ""; - - // Configure SSL. - config.Networking.Ssl.Enabled = true; - config.Networking.Ssl.ValidateCertificateChain = false; - config.Networking.Ssl.CertificatePath = "client.pfx"; - config.Networking.Ssl.CertificatePassword = ""; - }) - .With(args) // Pass command line args to the client - .Build(); - - await using var client = await HazelcastClientFactory.StartNewClientAsync(options); - - // Create a map on the cluster - await using var citiesMap = await client.GetMapAsync("cities"); - - // Add some data - await citiesMap.PutAsync(1, "London"); - await citiesMap.PutAsync(2, "New York"); - await citiesMap.PutAsync(3, "Tokyo"); - - // Output the data - var entries = citiesMap.GetEntriesAsync(); - - foreach (var entry in entries.Result) - { - Console.WriteLine($"{entry.Key} -> {entry.Value}"); - } - } -} ----- - -Following line returns a map proxy object for the `cities` map: - -[source,cs] ----- - // Create a map on the cluster - await using var citiesMap = await client.GetMapAsync("cities"); ----- - -If `cities` doesn't exist, it will be automatically created. All the clients connected to the same cluster will have access to the same map. - -With these lines, client adds data to the `cities` map. The first parameter is the key of the entry, the second one is the value. - -[source,cs] ----- - // Add some data - await citiesMap.PutAsync(1, "London"); - await citiesMap.PutAsync(2, "New York"); - await citiesMap.PutAsync(3, "Tokyo"); ----- - -Then, we get the data using the `GetEntriesAsync()` method and iterate over the results. - -[source,cs] ----- - // Output the data - var entries = citiesMap.GetEntriesAsync(); - - foreach (var entry in entries.Result) - { - Console.WriteLine($"{entry.Key} -> {entry.Value}"); - } ----- - -The output of this code is given below: - -[source,bash] ----- -2 -> New York -1 -> London -3 -> Tokyo ----- - -NOTE: Ordering of the keys is NOT enforced and results may NOT correspond to entry order. - - -== Summary - -In this tutorial, you learned how to get started with the Hazelcast .NET Client and put data into a distributed map. - -== See Also - -There are a lot of things that you can do with the .NET Client. For more, such as how you can query a map with predicates and SQL, -check out our https://github.com/hazelcast/hazelcast-csharp-client[.NET Client repository] and our https://hazelcast.github.io/hazelcast-csharp-client/versions.html[.NET API documentation] to better understand what is possible. - -If you have any questions, suggestions, or feedback please do not hesitate to reach out to us via https://slack.hazelcast.com/[Hazelcast Community Slack]. -Also, please take a look at https://github.com/hazelcast/hazelcast-csharp-client/issues[the issue list] if you would like to contribute to the client. - - diff --git a/docs/modules/tutorials/pages/go-client-getting-started.adoc b/docs/modules/tutorials/pages/go-client-getting-started.adoc deleted file mode 100644 index 43838499a..000000000 --- a/docs/modules/tutorials/pages/go-client-getting-started.adoc +++ /dev/null @@ -1,317 +0,0 @@ -= Getting Started with the Hazelcast Go Client -:description: This tutorial will get you started with the Hazelcast Go client and manipulate a map. - -== What You'll Learn - -{description} - -== Before you Begin - -* Go 1.15 or above -* https://hazelcast.com/products/viridian/[Hazelcast Viridian Cloud Account] -* A text editor or IDE - -== Start a Hazelcast Viridian Cloud Cluster - -1. Sign up for a Hazelcast Viridian Cloud account (free trial is available). -2. Log in to your Hazelcast Viridian Cloud account and start your trial by filling in the welcome questionnaire. -3. A Viridian cluster will be created automatically when you start your trial. -4. Press the Connect Cluster dialog and switch over to the Advanced setup tab for connection information needed below. -5. From the Advanced setup tab, download the keystore files and take note of your Cluster ID, Discovery Token and Password as you will need them later. - -== Setup a Hazelcast Client - -Create a new folder and navigate to it: - -[source] ----- -mkdir hazelcast-go-example -cd hazelcast-go-example ----- - -Initialize a new go module: - -[source,bash] ----- -go mod init example ----- - -Install Hazelcast Go client's latest version as a dependency: - -[source,bash] ----- -go get github.com/hazelcast/hazelcast-go-client@latest ----- - -Extract the keystore files you downloaded from Viridian into this directory. The files you need for this tutorial are: - -[source,bash] ----- -ca.pem -cert.pem -key.pem ----- - -== Understanding the Go Client - -The following section creates and starts a Hazelcast client with default configuration, connects to your Viridian cluster before shutting the client down at the end. - -Create a Go file named “example.go” and put the following code inside it: - -[source,go] ----- -package main - -import ( - "context" - "fmt" - - "github.com/hazelcast/hazelcast-go-client" -) - -func main() { - - // Connection details for cluster - config := hazelcast.Config{} - config.Cluster.Name = "" - - config.Cluster.Cloud.Enabled = true - config.Cluster.Cloud.Token = "" - - config.Cluster.Network.SSL.SetCAPath("ca.pem") - config.Cluster.Network.SSL.AddClientCertAndEncryptedKeyPath("cert.pem", "key.pem", "") - - // create the client and connect to the cluster - client, err := hazelcast.StartNewClientWithConfig(context.TODO(), config) - // error checking is omitted for brevity - - fmt.Println("Welcome to your Hazelcast Viridian Cluster!") - - defer client.Shutdown(context.TODO()) - - if err != nil { - panic(err) - } -} ----- - -To run this Go script, use the following command: - -[source,bash] ----- -go run example.go ----- - -== Understanding the Hazelcast SQL API - -Hazelcast SQL API is a Calcite SQL based interface to allow you to interact with Hazelcast much like any other datastore. - -In the following example, we will create a map and insert into it, entries where the keys are ids and the values are defined as an object representing a city. - -[source,go] ----- -package main - -import ( - "context" - "fmt" - "reflect" - - "github.com/hazelcast/hazelcast-go-client" - "github.com/hazelcast/hazelcast-go-client/logger" - "github.com/hazelcast/hazelcast-go-client/serialization" -) - -type CityDTO struct { - city string - country string - population int32 -} - -type CitySerializer struct{} - -func (s CitySerializer) Type() reflect.Type { - return reflect.TypeOf(CityDTO{}) -} - -func (s CitySerializer) TypeName() string { - return "CityDTO" -} - -func (s CitySerializer) Write(writer serialization.CompactWriter, value interface{}) { - city := value.(CityDTO) - - writer.WriteString("City", &city.city) - writer.WriteString("Country", &city.country) - writer.WriteInt32("Population", city.population) -} - -func (s CitySerializer) Read(reader serialization.CompactReader) interface{} { - return CityDTO{ - city: *reader.ReadString("city"), - country: *reader.ReadString("country"), - population: reader.ReadInt32("population"), - } -} - -func createMapping(ctx context.Context, client hazelcast.Client) error { - fmt.Println("Creating the mapping...") - - // Mapping is required for your distributed map to be queried over SQL. - // See: https://docs.hazelcast.com/hazelcast/latest/sql/mapping-to-maps - mappingQuery := ` - CREATE OR REPLACE MAPPING - cities ( - __key INT, - country VARCHAR, - city VARCHAR, - population INT) TYPE IMAP - OPTIONS ( - 'keyFormat' = 'int', - 'valueFormat' = 'compact', - 'valueCompactTypeName' = 'CityDTO') - ` - - _, err := client.SQL().Execute(ctx, mappingQuery) - if err != nil { - return err - } - - fmt.Println("OK.\n") - return nil -} - -func populateCities(ctx context.Context, client hazelcast.Client) error { - fmt.Println("Inserting data...") - - // Mapping is required for your distributed map to be queried over SQL. - // See: https://docs.hazelcast.com/hazelcast/latest/sql/mapping-to-maps - insertQuery := ` - INSERT INTO cities - (__key, city, country, population) VALUES - (1, 'London', 'United Kingdom', 9540576), - (2, 'Manchester', 'United Kingdom', 2770434), - (3, 'New York', 'United States', 19223191), - (4, 'Los Angeles', 'United States', 3985520), - (5, 'Istanbul', 'Türkiye', 15636243), - (6, 'Ankara', 'Türkiye', 5309690), - (7, 'Sao Paulo ', 'Brazil', 22429800) - ` - - _, err := client.SQL().Execute(ctx, "DELETE from cities") - if err != nil { - return err - } - _, err = client.SQL().Execute(ctx, insertQuery) - if err != nil { - return err - } - - fmt.Println("OK.\n") - return nil -} - -func fetchCities(ctx context.Context, client hazelcast.Client) error { - fmt.Println("Fetching cities...") - - result, err := client.SQL().Execute(ctx, "SELECT __key, this FROM cities") - if err != nil { - return err - } - defer result.Close() - - fmt.Println("OK.") - fmt.Println("--Results of SELECT __key, this FROM cities") - fmt.Printf("| %4s | %20s | %20s | %15s |\n", "id", "country", "city", "population") - - iter, err := result.Iterator() - for iter.HasNext() { - row, err := iter.Next() - - key, err := row.Get(0) - cityDTO, err := row.Get(1) - - fmt.Printf("| %4d | %20s | %20s | %15d |\n", key.(int32), cityDTO.(CityDTO).country, cityDTO.(CityDTO).city, cityDTO.(CityDTO).population) - - if err != nil { - return err - } - } - - fmt.Println("\n!! Hint !! You can execute your SQL queries on your Viridian cluster over the management center. \n 1. Go to 'Management Center' of your Hazelcast Viridian cluster. \n 2. Open the 'SQL Browser'. \n 3. Try to execute 'SELECT * FROM cities'.") - return nil -} - -/////////////////////////////////////////////////////// - -func main() { - - // Connection details for cluster - config := hazelcast.Config{} - config.Cluster.Name = "" - - config.Cluster.Cloud.Enabled = true - config.Cluster.Cloud.Token = "" - - config.Cluster.Network.SSL.SetCAPath("ca.pem") - config.Cluster.Network.SSL.AddClientCertAndEncryptedKeyPath("cert.pem", "key.pem", "") - - // Register Compact Serializers - config.Serialization.Compact.SetSerializers(CitySerializer{}) - - // Other environment propreties - config.Logger.Level = logger.FatalLevel - - ctx := context.TODO() - // create the client and connect to the cluster - client, err := hazelcast.StartNewClientWithConfig(ctx, config) - if err != nil { - panic(err) - } - - // - if err := createMapping(ctx, *client); err != nil { - panic(fmt.Errorf("creating mapping: %w", err)) - } - if err := populateCities(ctx, *client); err != nil { - panic(fmt.Errorf("populating cities: %w", err)) - } - if err := fetchCities(ctx, *client); err != nil { - panic(fmt.Errorf("fetching cities: %w", err)) - } - - if err := client.Shutdown(ctx); err != nil { - panic(err) - } -} ----- - -The output of this code is given below: - -[source,bash] ----- -Creating the mapping...OK. -Inserting data...OK. -Fetching cities...OK. ---Results of 'SELECT __key, this FROM cities' -| id | country | city | population | -| 2 | United Kingdom | Manchester | 2770434 | -| 6 | Türkiye | Ankara | 5309690 | -| 1 | United Kingdom | London | 9540576 | -| 7 | Brazil | Sao Paulo | 22429800 | -| 4 | United States | Los Angeles | 3985520 | -| 5 | Türkiye | Istanbul | 15636243 | -| 3 | United States | New York | 19223191 | ----- - -== Summary - -In this tutorial, you learned how to get started with the Hazelcast Go Client, connect to a Viridian instance and put data into a distributed map. - -== See Also - -There are a lot of things that you can do with the Go Client. For more, such as how you can query a map with predicates and SQL, -check out our https://github.com/hazelcast/hazelcast-go-client[Go Client repository] and our https://pkg.go.dev/github.com/hazelcast/hazelcast-go-client[Go API documentation] to better understand what is possible. - -If you have any questions, suggestions, or feedback please do not hesitate to reach out to us via https://slack.hazelcast.com/[Hazelcast Community Slack]. -Also, please take a look at https://github.com/hazelcast/hazelcast-go-client/issues[the issue list] if you would like to contribute to the client. diff --git a/docs/modules/tutorials/pages/hazelcast-platform-operator-expose-externally.adoc b/docs/modules/tutorials/pages/hazelcast-platform-operator-expose-externally.adoc deleted file mode 100644 index 07c9c707a..000000000 --- a/docs/modules/tutorials/pages/hazelcast-platform-operator-expose-externally.adoc +++ /dev/null @@ -1,574 +0,0 @@ -= Connect to Hazelcast from Outside Kubernetes -:description: In this tutorial, you'll connect to a Hazelcast cluster running in Kubernetes from outside of the Kubernetes environment. - -== What You’ll Learn - -{description} - -== Before you Begin - -* Up and running https://kubernetes.io/[Kubernetes] cluster -* Kubernetes command-line tool, https://kubernetes.io/docs/tasks/tools/#kubectl[kubectl] -* Deployed xref:operator:ROOT:get-started.adoc[Hazelcast Platform Operator] - -WARNING: This tutorial uses LoadBalancer services to connect to Hazelcast from outside of the Kubernetes cluster. Therefore, it is essential to ensure that your Kubernetes cluster can assign public IPs to LoadBalancer services. This is particularly important if you are using a local Kubernetes cluster such as Minikube or Kind. - -== Introduction - -There are two available options for Expose Externally feature of Hazelcast Platform Operator: - -- *Unisocket* - client requests are load balanced between Hazelcast members. - -- *Smart* - client connects to all members and sends requests directly to the members owning the data. - -Let’s see both approaches. - -== Unisocket - -The first option is to use the `Unisocket` type. This option will use the standard Kubernetes mechanism that automatically load balances the traffic to Hazelcast members. - -.Hazelcast Unisocket Client -image::unisocket.jpg[Hazelcast Unisocket Client] - -=== Start the Hazelcast Cluster - -Run the following command to create the Hazelcast cluster with Expose Externally feature enabled using Unisocket type. - -[source, shell] ----- -kubectl apply -f - < ----- --- - -Java:: -+ --- -[source, java] ----- -include::ROOT:example$/operator-expose-externally/java-unisocket/src/main/java/com/hazelcast/Main.java[] ----- --- - -NodeJS:: -+ --- -[source, javascript] ----- -include::ROOT:example$/operator-expose-externally/nodejs-unisocket/client.js[] ----- --- - -Go:: -+ --- -[source, go] ----- -include::ROOT:example$/operator-expose-externally/go-unisocket/main.go[] ----- --- - -Python:: -+ --- -[source, python] ----- -include::ROOT:example$/operator-expose-externally/python-unisocket/main.py[] ----- --- -.NET:: -+ --- -[source, cs] ----- -include::ROOT:example$/operator-expose-externally/dotnet-unisocket/csharp_example.cs[] ----- --- -==== - -Now you can start the application. - -[tabs] -==== - -CLC:: -+ --- -Run the following command to fill a map. - -[source, bash] ----- -for i in {1..10}; -do - clc -c hz map set --name map1 key-$i value-$i; -done ----- - -Run the following command to check the map size. - -[source, bash] ----- -clc -c hz map size --name map1 ----- --- - -Java:: -+ --- -[source, bash] ----- -cd java-unisocket -mvn package -java -jar target/*jar-with-dependencies*.jar ----- - -You should see the following output. - -[source, shell] ----- -Successful connection! -Starting to fill the map with random entries. -Current map size: 2 -Current map size: 3 -Current map size: 4 -.... -.... ----- --- - -NodeJS:: -+ --- -[source, bash] ----- -cd nodejs-unisocket -npm install -npm start ----- - -You should see the following output. - -[source, shell] ----- -Successful connection! -Starting to fill the map with random entries. -Current map size: 2 -Current map size: 3 -Current map size: 4 -.... -.... ----- --- - -Go:: -+ --- -[source, bash] ----- -cd go-unisocket -go run main.go ----- - -You should see the following output. - -[source, shell] ----- -Successful connection! -Starting to fill the map with random entries. -Current map size: 2 -Current map size: 3 -Current map size: 4 -.... -.... ----- --- - -Python:: -+ --- -[source, bash] ----- -cd python-unisocket -pip install -r requirements.txt -python main.py ----- - -You should see the following output. - -[source, shell] ----- -Successful connection! -Starting to fill the map with random entries. -Current map size: 2 -Current map size: 3 -Current map size: 4 -.... -.... ----- --- -.NET:: -+ --- -[source, bash] ----- -cd dotnet-unisocket -dotnet build -dotnet run ----- - -You should see the following output. - -[source, shell] ----- -Successful connection! -Starting to fill the map with random entries. -Current map size: 2 -Current map size: 3 -Current map size: 4 -.... -.... ----- --- - -==== - -== Smart Client - -The second option is to use the `Smart` type. With this option, each Hazelcast member will be exposed with its own service (it can be either `LoadBalancer` or `NodePort`). Hazelcast smart client is capable of mapping the given key with its owner member, which means that it sends the data directly to the member which contains the right data partition. - -.Hazelcast Smart Client -image::smart.jpg[Hazelcast Smart Client] - -=== Start the Hazelcast Cluster - -Run the following command to create the Hazelcast cluster with Expose Externally feature enabled using Smart type. - -[source, shell] ----- -kubectl apply -f - < ----- --- - -Java:: -+ --- -[source, java] ----- -include::ROOT:example$/operator-expose-externally/java/src/main/java/com/hazelcast/Main.java[] ----- --- - -NodeJS:: -+ --- -[source, javascript] ----- -include::ROOT:example$/operator-expose-externally/nodejs/client.js[] ----- --- - -Go:: -+ --- -[source, go] ----- -include::ROOT:example$/operator-expose-externally/go/main.go[] ----- --- - -Python:: -+ --- -[source, python] ----- -include::ROOT:example$/operator-expose-externally/python/main.py[] ----- --- -.Net:: -+ --- -[source, cs] ----- -include::ROOT:example$/operator-expose-externally/dotnet-unisocket/csharp_example.cs[] ----- --- -==== - - -Now you can start the application. - -[tabs] -==== - -CLC:: -+ --- -Run the following command to fill a map. - -[source, bash] ----- -for i in {1..10}; -do - clc -c hz map set --name map1 key-$i value-$i; -done ----- - -Run the following command to check the map size. - -[source, bash] ----- -clc -c hz map size --name map1 ----- --- - -Java:: -+ --- -[source, bash] ----- -cd java -mvn package -java -jar target/*jar-with-dependencies*.jar ----- - -You should see the following output. - -[source, shell] ----- -Successful connection! -Starting to fill the map with random entries. -Current map size: 2 -Current map size: 3 -Current map size: 4 -.... -.... ----- --- - -NodeJS:: -+ --- -[source, bash] ----- -cd nodejs -npm install -npm start ----- - -You should see the following output. - -[source, shell] ----- -Successful connection! -Starting to fill the map with random entries. -Current map size: 2 -Current map size: 3 -Current map size: 4 -.... -.... ----- --- - -Go:: -+ --- -[source, bash] ----- -cd go -go run main.go ----- - -You should see the following output. - -[source, shell] ----- -Successful connection! -Starting to fill the map with random entries. -Current map size: 2 -Current map size: 3 -Current map size: 4 -.... -.... ----- --- - -Python:: -+ --- -[source, bash] ----- -cd python -pip install -r requirements.txt -python main.py ----- - -You should see the following output. - -[source, shell] ----- -Successful connection! -Starting to fill the map with random entries. -Current map size: 2 -Current map size: 3 -Current map size: 4 -.... -.... ----- --- -.NET:: -+ --- -[source, bash] ----- -cd dotnet -dotnet build -dotnet run ----- - -You should see the following output. - -[source, shell] ----- -Successful connection! -Starting to fill the map with random entries. -Current map size: 2 -Current map size: 3 -Current map size: 4 -.... -.... ----- --- - -==== - -== Clean Up - -To clean up the created resources remove the Hazelcast Custom Resource. - -[source, shell] ----- -kubectl delete hazelcast my-hazelcast ----- - -== See Also - -- xref:operator:ROOT:index.adoc[] -- xref:kubernetes-external-client.adoc[] diff --git a/docs/modules/tutorials/pages/java-client-getting-started.adoc b/docs/modules/tutorials/pages/java-client-getting-started.adoc deleted file mode 100644 index 2e95fa8bb..000000000 --- a/docs/modules/tutorials/pages/java-client-getting-started.adoc +++ /dev/null @@ -1,435 +0,0 @@ -= Getting Started with the Hazelcast Java Client -:description: This tutorial will get you started with the Hazelcast Java client and manipulate a map. - -== What You'll Learn - -{description} - -== Before you Begin - -Before starting this tutorial, make sure the following prerequisites are met: - -* JDK 11.0 or above -* https://hazelcast.com/products/viridian/[Hazelcast Viridian Cloud Account] -* An IDE - -== Start a Hazelcast Viridian Cloud Cluster - -1. Sign up for a Hazelcast Viridian Cloud account (free trial is available). -2. Log in to your Hazelcast Viridian Cloud account and start your trial by filling in the welcome questionnaire. -3. A Viridian cluster will be created automatically when you start your trial. -4. Press the Connect Cluster dialog and switch over to the Advanced setup tab for connection information needed below. -5. From the Advanced setup tab, download the keystore files and take note of your Cluster ID, Discovery Token and Password as you will need them later. - -== Setup a Hazelcast Client - -Create a new folder and navigate to it: - -[source] ----- -mkdir hazelcast-java-example -cd hazelcast-java-example ----- - -Download the latest version of Hazelcast Enterprise zip slim from https://hazelcast.com/get-started/download/[here] and extract the Hazelcast Enterprise jar into this directory: - -[source] ----- -hazelcast-enterprise-5.3.1.jar ----- - -Extract the keystore files you downloaded from Viridian into this directory. The files you need for this tutorial are: - -[source,bash] ----- -client.keystore -client.pfx -client.truststore ----- - -To understand and use the client, review the https://docs.hazelcast.com/hazelcast/5.3/clients/java#hide-nav[Java client documentation] to better understand what is possible. - -== Understanding the Java Client - -The following section creates and starts a Hazelcast client with default configuration, connects to your Viridian cluster before shutting the client down at the end. - -Create a Java file named “Example.java” and put the following code inside it: - -[source,java] ----- -import java.util.Properties; - -import com.hazelcast.client.HazelcastClient; -import com.hazelcast.client.config.ClientConfig; -import com.hazelcast.config.SSLConfig; -import com.hazelcast.core.HazelcastInstance; - -public class Example { - - public static void main(String[] args) throws Exception { - ClientConfig config = new ClientConfig(); - - // Your Viridian cluster name. - config.setClusterName(""); - - // Your discovery token to connect Viridian cluster. - config.getNetworkConfig().getCloudConfig() - .setDiscoveryToken("") - .setEnabled(true); - - // Configure SSL - ClassLoader classLoader = ClientWithSsl.class.getClassLoader(); - Properties props = new Properties(); - props.setProperty("javax.net.ssl.keyStore", classLoader.getResource("client.keystore").toURI().getPath()); - props.setProperty("javax.net.ssl.keyStorePassword", ""); - props.setProperty("javax.net.ssl.trustStore", - classLoader.getResource("client.truststore").toURI().getPath()); - props.setProperty("javax.net.ssl.trustStorePassword", ""); - config.getNetworkConfig().setSSLConfig(new SSLConfig().setEnabled(true).setProperties(props)); - - // Create client - HazelcastInstance client = HazelcastClient.newHazelcastClient(config); - - System.out.println("Welcome to your Hazelcast Viridian Cluster!") - - client.shutdown(); - } -} ----- - -== Understanding the Hazelcast SQL API - -Hazelcast SQL API is a Calcite SQL based interface to allow you to interact with Hazelcast much like any other datastore. - -In the following example, we will create a map and insert into it, entries where the keys are ids and the values are defined as an object representing a city. - -[source,java] ----- -import java.util.Properties; - -import com.hazelcast.client.HazelcastClient; -import com.hazelcast.client.config.ClientConfig; -import com.hazelcast.config.SSLConfig; -import com.hazelcast.core.HazelcastInstance; - -import com.hazelcast.nio.serialization.compact.CompactReader; -import com.hazelcast.nio.serialization.compact.CompactSerializer; -import com.hazelcast.nio.serialization.compact.CompactWriter; -import com.hazelcast.sql.SqlResult; -import com.hazelcast.sql.SqlRow; -import com.hazelcast.sql.SqlService; - -public class Example { - - public final class CityDTO { - - private final String country; - - private final String city; - - private final int population; - - public CityDTO(String country, String city, int population) { - this.country = country; - this.city = city; - this.population = population; - } - - public String getCountry() { - return country; - } - - public String getCity() { - return city; - } - - public int getPopulation() { - return population; - } - } - - public final class CitySerializer implements CompactSerializer { - @Override - public CityDTO read(CompactReader compactReader) { - return new CityDTO(compactReader.readString("country"), - compactReader.readString("city"), - compactReader.readInt32("population")); - } - - @Override - public void write(CompactWriter compactWriter, CityDTO city) { - compactWriter.writeString("country", city.getCountry()); - compactWriter.writeString("city", city.getCity()); - compactWriter.writeInt32("population", city.getPopulation()); - } - - @Override - public String getTypeName() { - return "CityDTO"; - } - - @Override - public Class getCompactClass() { - return CityDTO.class; - } - } - - public static void main(String[] args) throws Exception { - ClientConfig config = new ClientConfig(); - - // Connection details for cluster - config.setClusterName(""); - - config.getNetworkConfig().getCloudConfig() - .setDiscoveryToken("") - .setEnabled(true); - - ClassLoader classLoader = Example.class.getClassLoader(); - Properties props = new Properties(); - props.setProperty("javax.net.ssl.keyStore", classLoader.getResource("client.keystore").toURI().getPath()); - props.setProperty("javax.net.ssl.keyStorePassword", ""); - props.setProperty("javax.net.ssl.trustStore", classLoader.getResource("client.truststore").toURI().getPath()); - props.setProperty("javax.net.ssl.trustStorePassword", ""); - config.getNetworkConfig().setSSLConfig(new SSLConfig().setEnabled(true).setProperties(props)); - - // Register Compact Serializers - config.getSerializationConfig().getCompactSerializationConfig() - .addSerializer(new Example().new CitySerializer()); - - // Connect to your Hazelcast Cluster - HazelcastInstance client = HazelcastClient.newHazelcastClient(config); - - try { - // Create a map on the cluster - createMapping(client.getSql()); - - // Add some data - insertCities(client); - - // Output the data - fetchCities(client.getSql()); - - } finally { - client.shutdown(); - } - } - - private static void createMapping(SqlService sqlService) { - // See: https://docs.hazelcast.com/hazelcast/latest/sql/mapping-to-maps#compact-objects - System.out.print("\nCreating mapping..."); - - String mappingSql = "" - + "CREATE OR REPLACE MAPPING cities(" - + " __key INT," - + " country VARCHAR," - + " city VARCHAR," - + " population INT" - + ") TYPE IMap" - + " OPTIONS (" - + " 'keyFormat' = 'int'," - + " 'valueFormat' = 'compact'," - + " 'valueCompactTypeName' = 'Example$CityDTO'" - + " )"; - - try (SqlResult ignored = sqlService.execute(mappingSql)) { - System.out.print("OK."); - } catch (Exception ex) { - System.out.print("FAILED. " + ex.getMessage()); - } - } - - private static void insertCities(HazelcastInstance client) { - try { - String deleteQuery = "DELETE from cities"; - - String insertQuery = "INSERT INTO cities " - + "(__key, city, country, population) VALUES" - + "(1, 'London', 'United Kingdom', 9540576)," - + "(2, 'Manchester', 'United Kingdom', 2770434)," - + "(3, 'New York', 'United States', 19223191)," - + "(4, 'Los Angeles', 'United States', 3985520)," - + "(5, 'Istanbul', 'Türkiye', 15636243)," - + "(6, 'Ankara', 'Türkiye', 5309690)," - + "(7, 'Sao Paulo ', 'Brazil', 22429800)"; - - System.out.print("\nInserting data..."); - client.getSql().execute(deleteQuery); - client.getSql().execute(insertQuery); - System.out.print("OK."); - } catch (Exception ex) { - System.out.print("FAILED. " + ex.getMessage()); - } - } - - private static void fetchCities(SqlService sqlService) { - System.out.print("\nFetching cities..."); - - try (SqlResult result = sqlService.execute("SELECT __key, this FROM cities")) { - System.out.print("OK.\n"); - System.out.println("--Results of 'SELECT __key, this FROM cities'"); - - System.out.printf("%4s | %20s | %20s | %15s |%n", "id", "country", "city", "population"); - for (SqlRow row : result) { - int id = row.getObject("__key"); - CityDTO cityDTO = row.getObject("this"); - System.out.printf("%4s | %20s | %20s | %15s |%n", - id, - cityDTO.getCountry(), - cityDTO.getCity(), - cityDTO.getPopulation() - ); - } - } catch (Exception ex) { - System.out.print("FAILED. " + ex.getMessage()); - } - } -} ----- - -The output of this code is given below: - -[source,bash] ----- -Creating the mapping...OK. -Inserting data...OK. -Fetching cities...OK. ---Results of 'SELECT __key, this FROM cities' -| id | country | city | population | -| 2 | United Kingdom | Manchester | 2770434 | -| 6 | Türkiye | Ankara | 5309690 | -| 1 | United Kingdom | London | 9540576 | -| 7 | Brazil | Sao Paulo | 22429800 | -| 4 | United States | Los Angeles | 3985520 | -| 5 | Türkiye | Istanbul | 15636243 | -| 3 | United States | New York | 19223191 | ----- - -NOTE: Ordering of the keys is NOT enforced and results may NOT correspond to insertion order. - -== Understanding the Hazelcast IMap API - -A Hazelcast Map is a distributed key-value store, similar to Python dictionary. You can store key-value pairs in a Hazelcast Map. - -In the following example, we will work with map entries where the keys are ids and the values are defined as a string representing a city name. - -[source,java] ----- -import java.util.Map; -import java.util.Properties; -import java.util.Set; - -import com.hazelcast.client.HazelcastClient; -import com.hazelcast.client.config.ClientConfig; -import com.hazelcast.config.SSLConfig; -import com.hazelcast.core.HazelcastInstance; -import com.hazelcast.map.IMap; - -public class Example { - - public static void main(String[] args) throws Exception { - ClientConfig config = new ClientConfig(); - - // Your Viridian cluster name. - config.setClusterName(""); - - // Your discovery token to connect Viridian cluster. - config.getNetworkConfig().getCloudConfig() - .setDiscoveryToken("") - .setEnabled(true); - - // Configure SSL - ClassLoader classLoader = ClientWithSsl.class.getClassLoader(); - Properties props = new Properties(); - props.setProperty("javax.net.ssl.keyStore", classLoader.getResource("client.keystore").toURI().getPath()); - props.setProperty("javax.net.ssl.keyStorePassword", ""); - props.setProperty("javax.net.ssl.trustStore", classLoader.getResource("client.truststore").toURI().getPath()); - props.setProperty("javax.net.ssl.trustStorePassword", ""); - config.getNetworkConfig().setSSLConfig(new SSLConfig().setEnabled(true).setProperties(props)); - - // Create client - HazelcastInstance client = HazelcastClient.newHazelcastClient(config); - - try { - // Create a map on the cluster - IMap citiesMap = client.getMap("cities"); - - // Clear the map - citiesMap.clear(); - - // Add some data - citiesMap.put(1, "London"); - citiesMap.put(2, "New York"); - citiesMap.put(3, "Tokyo"); - - // Output the data - Set> entries = citiesMap.entrySet(); - - for (Map.Entry entry : entries) - { - System.out.println(entry.getKey() + " -> " + entry.getValue() ); - } - } finally { - client.shutdown(); - } - } -} ----- - -Following line returns a map proxy object for the `cities` map: - -[source,java] ----- - // Create a map on the cluster - IMap citiesMap = client.getMap("cities"); ----- - -If `cities` doesn't exist, it will be automatically created. All the clients connected to the same cluster will have access to the same map. - -With these lines, client adds data to the `cities` map. The first parameter is the key of the entry, the second one is the value. - -[source,java] ----- - // Add some data - citiesMap.put(1, "London"); - citiesMap.put(2, "New York"); - citiesMap.put(3, "Tokyo"); ----- - -Then, we get the data using the `entrySet()` method and iterate over the results. - -[source,java] ----- - // Output the data - Set> entries = citiesMap.entrySet(); - - for (Map.Entry entry : entries) - { - System.out.println(entry.getKey() + " -> " + entry.getValue() ); - } ----- - -The output of this code is given below: - -[source,bash] ----- -2 -> New York -1 -> London -3 -> Tokyo ----- - -NOTE: Ordering of the keys is NOT enforced and results may NOT correspond to entry order. - - -== Summary - -In this tutorial, you learned how to get started with the Hazelcast Java Client, connect to a Viridian instance and put data into a distributed map. - -== See Also - -There are a lot of things that you can do with the Java Client. For more, such as how you can query a map with predicates and SQL, -check out our https://github.com/hazelcast/hazelcast[Hazelcast repository] and our https://docs.hazelcast.com/hazelcast/5.3/clients/java#hide-nav[Java client documentation] to better understand what is possible. - -If you have any questions, suggestions, or feedback please do not hesitate to reach out to us via https://slack.hazelcast.com/[Hazelcast Community Slack]. -Also, please take a look at https://github.com/hazelcast/hazelcast/issues[the issue list] if you would like to contribute to the client. - - diff --git a/docs/modules/tutorials/pages/join-two-streams.adoc b/docs/modules/tutorials/pages/join-two-streams.adoc deleted file mode 100644 index 6f442afa8..000000000 --- a/docs/modules/tutorials/pages/join-two-streams.adoc +++ /dev/null @@ -1,361 +0,0 @@ -= Stream-To-Stream Joins with SQL -:description: Learn how to join two streams of data and process the results, using SQL. - -{description} - -[.interactive-button] -link:https://gitpod.io/#https://github.com/hazelcast-guides/stream-to-stream-joins[Try it in your browser,window=_blank] - -== Context - -A stream of data is an ongoing delivery of data events. These events are often of the same type. For example, a stream may contain click events on a website. - -If you have two or more streams of related data, you can join them together on a related field, process them, and store the result. - -== Example Use Case - -You have two streams. One stream contains events for new orders and the other contains events for shipped orders. You need to join these two streams to find out which orders have been successfully shipped within seven days, and from which warehouse they were shipped. - -== Before you Begin - -Before starting this tutorial, make sure that you have the following prerequisites: - -* link:https://docs.docker.com/compose/install/[Docker Compose] -* link:https://git-scm.com/book/en/v2/Getting-Started-Installing-Git[Git] - -== Step 1. Clone the Project - -To set up the project, you need to download the code from GitHub. - -. Clone the GitHub repository. -+ -[tabs] -==== -HTTPS:: -+ --- -```bash -git clone https://github.com/hazelcast-guides/stream-to-stream-joins.git -cd stream-to-stream-joins -``` --- -SSH:: -+ --- -```bash -git clone git@github.com:hazelcast-guides/stream-to-stream-joins.git -cd stream-to-stream-joins -``` --- -==== - -== Step 2. Start the Docker Containers - -In this step, you'll use Docker Compose to start all the Docker containers, including a Kafka broker, Hazelcast Platform, and Management Center. - -```bash -docker compose up -d -``` - -You should see the following: - -``` -[+] Running 4/4 - ⠿ Container zookeeper Started 0.7s - ⠿ Container management-center Started 0.6s - ⠿ Container hazelcast Started 0.7s - ⠿ Container broker Started 1.2s -``` - -The Docker containers are running in detached mode. You can see that they are running, using the following command: - -``` -docker ps -``` - -To see the logs of your Hazelcast member, use the following command: - -``` -docker logs hazelcast -``` - -You should see that you have a single member running in the cluster. - -``` -Members {size:1, ver:1} [ - Member [172.19.0.4]:5701 - 15116025-342b-43c0-83f7-a2a90f0281ce this -] -``` - -== Step 3. Create Two Kafka Topics - -To create the Kafka topics, you'll use the `kafka-console-producer` script that's built into the Kafka broker. - -. Create the `orders` topic and add some records to it. -+ -```bash -docker exec -i broker kafka-console-producer --broker-list broker:9092 --topic orders < orders.jsonl -``` - -. Create the `shipments` topic and add some records to it. -+ -```bash -docker exec -i broker kafka-console-producer --broker-list broker:9092 --topic shipments < shipments.jsonl -``` - -== Step 4. Create Mappings to the Kafka Topics - -In this step, you'll use the SQL shell in Hazelcast to create a mapping to the Kafka topics. With this mapping, Hazelcast will be able to receive the event streams. - -. Open the SQL shell. -+ -```bash -docker exec -it hazelcast hz-cli sql -``` - -. Create a mapping to the `orders` topic. -+ -```sql -CREATE OR REPLACE MAPPING orders( - id INT, - order_ts TIMESTAMP WITH TIME ZONE, - total_amount DOUBLE, - customer_name VARCHAR) -TYPE Kafka -OPTIONS ( - 'keyFormat' = 'int', <1> - 'valueFormat' = 'json-flat', <2> - 'auto.offset.reset' = 'earliest', <3> - 'bootstrap.servers' = 'broker:9092'); <4> -``` -+ -<1> The kafka record key, which is the ID of the orders and shipments. -<2> Map the Kafka records to JSON, using the `json-flat` format. This format maps each top-level JSON field to its own column. -<3> Tell Hazelcast to read from the beginning of the topic so that you can read the values that you already added to it. -<4> The address of the Kafka broker that Hazelcast connects to. - -. Make sure that the mapping is correct by running a streaming query on the topic. -+ -```sql -SELECT * FROM orders; -``` -+ -``` -+------------+-------------------------+-------------------------+--------------------+ -| id|order_ts | total_amount|customer_name | -+------------+-------------------------+-------------------------+--------------------+ -| 1|2022-03-29T06:01:18Z | 133548.84|Amal | -| 2|2022-03-29T17:02:20Z | 164839.31|Alex | -| 3|2022-03-29T13:44:10Z | 90427.66|Hao | -| 4|2022-03-29T11:58:25Z | 33462.11|Cruz | -``` - -. Press kbd:[Ctrl+C] to exit the streaming query. - -. Create a mapping to the `shipments` topic. -+ -```sql -CREATE OR REPLACE MAPPING shipments( - id VARCHAR, - ship_ts TIMESTAMP WITH TIME ZONE, - order_id INT, - warehouse VARCHAR -) -TYPE Kafka -OPTIONS ( - 'keyFormat' = 'varchar', - 'valueFormat' = 'json-flat', - 'auto.offset.reset' = 'earliest', - 'bootstrap.servers' = 'broker:9092'); -``` - -. Make sure that the mapping is correct by running a streaming query on the topic. -+ -```sql -SELECT * FROM shipments; -``` -+ -``` -+--------------------+-------------------------+------------+--------------------+ -|id |ship_ts | order_id|warehouse | -+--------------------+-------------------------+------------+--------------------+ -|ship-ch83360 |2022-03-31T18:13:39Z | 1|UPS | -|ship-xf72808 |2022-03-31T02:04:13Z | 2|UPS | -|ship-kr47454 |2022-03-31T20:47:09Z | 3|DHL | -``` - -. Press kbd:[Ctrl+C] to exit the streaming query. - -== Step 5. Join the Two Streams - -In this step, you'll join the two streams to get insights about shipments that are sent within 7 days of the order. - -You can join streams in Hazelcast only on a table that defines a allowed lag for late events. Hazelcast drops events that are later than the defined lag and does not include them in the result set. - -. Drop late events when they are one minute or later behind the current latest event. -+ -```sql -CREATE OR REPLACE VIEW shipments_ordered AS - SELECT * FROM TABLE(IMPOSE_ORDER( - TABLE shipments, - DESCRIPTOR(ship_ts), <1> - INTERVAL '1' MINUTE)); <2> -``` -+ -```sql -CREATE OR REPLACE VIEW orders_ordered AS - SELECT * FROM TABLE(IMPOSE_ORDER( - TABLE orders, - DESCRIPTOR(order_ts), <1> - INTERVAL '1' MINUTE)); <2> -``` -+ -<1> The field that Hazelcast reads to compare to the lag. This field must be a timestamp. -<2> An allowed lag of one minute. - -. Join the two streams. This query finds orders that were shipped within 7 days of being placed. -+ -```sql -SELECT o.id AS order_id, - o.order_ts, - o.total_amount, - o.customer_name, - s.id AS shipment_id, - s.ship_ts, - s.warehouse -FROM orders_ordered o JOIN shipments_ordered s <1> -ON o.id = s.order_id AND s.ship_ts BETWEEN o.order_ts AND o.order_ts + INTERVAL '7' DAYS; <2> -``` -+ -<1> The inner join makes sure that results are output only for orders that have successfully shipped. The query must find a match on both sides of the join. -<2> A window duration of seven days ignores orders whose shipments don’t occur within 7 days of purchasing. Another added benefit of limiting this query to 7 days of data is that it limits the amount of memory that the query requires. - -``` -+------------+-------------------------+-------------------------+--------------------+--------------------+-------------------------+--------------------+ -| order_id|order_ts | total_amount|customer_name |shipment_id |ship_ts |warehouse | -+------------+-------------------------+-------------------------+--------------------+--------------------+-------------------------+--------------------+ -| 1|2022-03-29T06:01:18Z | 133548.84|Amal |ship-ch83360 |2022-03-31T18:13:39Z |UPS | -| 2|2022-03-29T17:02:20Z | 164839.31|Alex |ship-xf72808 |2022-03-31T02:04:13Z |UPS | -| 3|2022-03-29T13:44:10Z | 90427.66|Hao |ship-kr47454 |2022-03-31T20:47:09Z |DHL | -``` - -== Step 6. Create a Materialized View - -In this step, you'll define a job to run this streaming query in the background and store the results in a materialized view, using a Hazelcast map. - -. Create a mapping to a Hazelcast map called `orders_shipped_within_7_days`. -+ -```sql -CREATE OR REPLACE MAPPING orders_shipped_within_7_days( - __key INT, <1> - order_ts TIMESTAMP WITH TIME ZONE, <2> - total_amount DOUBLE, - customer_name VARCHAR, - shipment_id VARCHAR, - ship_ts TIMESTAMP WITH TIME ZONE, - warehouse VARCHAR -) -TYPE IMAP - OPTIONS ( - 'keyFormat' = 'int', <1> - 'valueFormat' = 'json-flat'); <2> -``` -+ -<1> The first column must be named `__key`. This column is mapped to the key of map entries. -<2> The other columns must appear in the same order as the streaming query results so that the data types are mapped correctly. - -. Create the job. -+ -```sql -CREATE JOB get_orders_shipped_within_7_days AS - SINK INTO orders_shipped_within_7_days <1> - SELECT o.id AS __key, <2> - o.order_ts, - o.total_amount, - o.customer_name, - s.id AS shipment_id, - s.ship_ts, - s.warehouse - FROM orders_ordered o JOIN shipments_ordered s <1> - ON o.id = s.order_id AND s.ship_ts BETWEEN o.order_ts AND o.order_ts + INTERVAL '7' DAYS; -``` -+ -<1> Insert the results into the `orders_shipped_within_7_days ` map. -<2> Make sure that the selected fields are in the same order as the mapping to the `orders_shipped_within_7_days ` map. - -. Query the map to make sure that the job is working. -+ -```sql -SELECT * FROM orders_shipped_within_7_days; -``` - -You should see the following: - -``` -+------------+-------------------------+-------------------------+--------------------+--------------------+-------------------------+--------------------+ -| __key|order_ts | total_amount|customer_name |shipment_id |ship_ts |warehouse | -+------------+-------------------------+-------------------------+--------------------+--------------------+-------------------------+--------------------+ -| 2|2022-03-29T17:02:20Z | 164839.31|Alex |ship-xf72808 |2022-03-31T02:04:13Z |UPS | -| 1|2022-03-29T06:01:18Z | 133548.84|Amal |ship-ch83360 |2022-03-31T18:13:39Z |UPS | -| 3|2022-03-29T13:44:10Z | 90427.66|Hao |ship-kr47454 |2022-03-31T20:47:09Z |DHL | -+------------+-------------------------+-------------------------+--------------------+--------------------+-------------------------+--------------------+ -``` - -If you left this query running, it would continue to add new results for orders shipped within 7 days. You can connect your applications to the Hazelcast cluster and query this map to get further insights. - -== Step 7. Clean Up - -Stop and remove your Docker containers. - -```bash -docker compose stop -docker compose rm -``` - -== Summary - -In this tutorial, you learned: - -- How to get deeper insights from two related streams by joining them together. -- How to run the streaming query in the background and store the results in a materialized view, using a job. - -== Next Steps - -.Run on Hazelcast {hazelcast-cloud} -[%collapsible] -==== -Learn how to xref:create-materialized-view-from-kafka.adoc[run streaming queries on Hazelcast {hazelcast-cloud}]. -==== - -.Persist mappings and maps -[%collapsible] -==== -By default, mappings and maps are not persisted. When you stop your cluster, all mappings and map data are deleted. -To persist this data, you can enable the xref:hazelcast:storage:persistence.adoc[Persistence] feature in the cluster configuration. Or, you can use Hazelcast {hazelcast-cloud}, which is persists this data by default. For an introduction to querying Kafka streams in Hazelcast {hazelcast-cloud}, see xref:tutorials:ROOT:create-materialized-view-from-kafka.adoc[Query Streams from Confluent Cloud]. -==== - -.Manage memory -[%collapsible] -==== -The materialized view would continue to store more and more results as new orders and shipment events are generated. To control the size of the map and the amount of memory it consumes, you can configure it with limits. See xref:hazelcast:data-structures:managing-map-memory.adoc[Managing Map Memory]. -==== - -.Manage jobs -[%collapsible] -==== -To manage your streaming job, see xref:hazelcast:pipelines:job-management.adoc[]. -==== - -.Explore Management Center -[%collapsible] -==== -To manage and monitor your cluster, you can use Management Center. This project runs Management Center at http://locahost:8080. See the xref:management-center:getting-started:overview.adoc[Management Center documentation] for details. -==== - -== See Also - -- xref:hazelcast:sql:sql-overview.adoc[SQL reference]. - -- xref:hazelcast:sql:querying-streams.adoc[]. - -- xref:hazelcast:sql:working-with-json.adoc[]. diff --git a/docs/modules/tutorials/pages/nodejs-client-getting-started.adoc b/docs/modules/tutorials/pages/nodejs-client-getting-started.adoc deleted file mode 100644 index 828ea4159..000000000 --- a/docs/modules/tutorials/pages/nodejs-client-getting-started.adoc +++ /dev/null @@ -1,565 +0,0 @@ -= Getting Started with the Hazelcast Node.js Client -:description: This tutorial will get you started with the Hazelcast Node.js client and manipulate a map. - -== What You'll Learn - -{description} - -== Before you Begin - -* Node.js 10.4 or above -* https://hazelcast.com/products/viridian/[Hazelcast Viridian Cloud Account] -* A text editor or IDE - -== Start a Hazelcast Viridian Cloud Cluster - -1. Sign up for a Hazelcast Viridian Cloud account (free trial is available). -2. Log in to your Hazelcast Viridian Cloud account and start your trial by filling in the welcome questionnaire. -3. A Viridian cluster will be created automatically when you start your trial. -4. Press the Connect Cluster dialog and switch over to the Advanced setup tab for connection information needed below. -5. From the Advanced setup tab, download the keystore files and take note of your Cluster ID, Discovery Token and Password as you will need them later. - -== Setup a Hazelcast Client - -Create a new folder and navigate to it: - -[source] ----- -mkdir hazelcast-nodejs-example -cd hazelcast-nodejs-example ----- - -Initialize a new npm package and choose default values when asked: - -[source,bash] ----- -npm init ----- - -Install Hazelcast Node.js client's latest version: - -[source,bash] ----- -npm install --save hazelcast-client ----- - -Extract the keystore files you downloaded from Viridian into this directory. The files you need for this tutorial are: - -[source,bash] ----- -ca.pem -cert.pem -key.pem ----- - -== Understanding the Node.js Client - -The following section creates and starts a Hazelcast client with default configuration, connects to your Viridian cluster before shutting the client down at the end. - -Create a JavaScript file named “index.js” and put the following code inside it: - -[source,javascript] ----- -'use strict'; - -const { Client } = require('hazelcast-client'); -const fs = require('fs'); -const path = require('path'); -const process = require('process'); -const sprintf= require('sprintf-js').sprintf; - -(async () => { - - const client = await Client.newHazelcastClient({ - clusterName: '', - - // Connection details for cluster - network: { - hazelcastCloud: { - discoveryToken: '', - }, - - ssl: { - enabled: true, - sslOptions: { - ca: [fs.readFileSync(path.resolve(path.join(__dirname, 'ca.pem')))], - cert: [fs.readFileSync(path.resolve(path.join(__dirname, 'cert.pem')))], - key: [fs.readFileSync(path.resolve(path.join(__dirname, 'key.pem')))], - passphrase: '', - checkServerIdentity: () => null - }, - }, - }, - - // Other environment propreties - properties: { - 'hazelcast.logging.level': 'WARN' // this property value is case-insensitive - }, - }); - - process.stdout.write('Welcome to your Hazelcast Viridian Cluster!'); - - await client.shutdown(); - -})().catch(err => { - process.stderr.write(`An error occured: ${err}\n`); -}); ----- - -To run this Node.js script, use the following command: - -[source,bash] ----- -node index.js ----- - -The majority of the client methods return promises using the https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function[async/await] syntax, -but you can use the regular https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then[then] / https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch[catch] -syntax, too. - -== Understanding the Hazelcast SQL API - -Hazelcast SQL API is a Calcite SQL based interface to allow you to interact with Hazelcast much like any other datastore. - -In the following example, we will create a map and insert into it, entries where the keys are ids and the values are defined as an object representing a city. - -NOTE: SSL certificate files are available from the Python client download available from Viridian. - -[source,javascript] ----- -'use strict'; - -const { Client } = require('hazelcast-client'); -const fs = require('fs'); -const path = require('path'); -const process = require('process'); -const sprintf= require('sprintf-js').sprintf; - -class CityDTO { - constructor(city, country, population) { - this.city = city; - this.country = country; - this.population = population; - } -} - -class CitySerializer { - - getClass() { - return CityDTO; - } - - getTypeName() { - return 'CityDTO' - } - - write(writer, cityDTO) { - writer.writeString('city', cityDTO.city); - writer.writeString('country', cityDTO.country); - writer.writeInt32('population', cityDTO.population); - } - - read(reader) { - const city = reader.readString('city'); - const country = reader.readString('country'); - const population = reader.readInt32('population'); - - return new CityDTO(city, country, population); - } -} - -async function createMapping(client) { - process.stdout.write('Creating the mapping...'); - - // Mapping is required for your distributed map to be queried over SQL. - // See: https://docs.hazelcast.com/hazelcast/latest/sql/mapping-to-maps - const mappingQuery = ` - CREATE OR REPLACE MAPPING - cities ( - __key INT, - country VARCHAR, - city VARCHAR, - population INT) TYPE IMAP - OPTIONS ( - 'keyFormat' = 'int', - 'valueFormat' = 'compact', - 'valueCompactTypeName' = 'CityDTO') - `; - - await client.getSql().execute(mappingQuery); - process.stdout.write('OK.\n'); -} - -async function populateCities(client) { - process.stdout.write('Inserting data...'); - - // Mapping is required for your distributed map to be queried over SQL. - // See: https://docs.hazelcast.com/hazelcast/latest/sql/mapping-to-maps - const insertQuery = ` - INSERT INTO cities - (__key, city, country, population) VALUES - (1, 'London', 'United Kingdom', 9540576), - (2, 'Manchester', 'United Kingdom', 2770434), - (3, 'New York', 'United States', 19223191), - (4, 'Los Angeles', 'United States', 3985520), - (5, 'Istanbul', 'Türkiye', 15636243), - (6, 'Ankara', 'Türkiye', 5309690), - (7, 'Sao Paulo ', 'Brazil', 22429800) - `; - - try { - await client.getSql().execute('DELETE from cities'); - await client.getSql().execute(insertQuery); - - process.stdout.write('OK.\n'); - } catch (error) { - process.stderr.write('FAILED.\n', error) - } -} - -async function fetchCities(client) { - process.stdout.write('Fetching cities...'); - - const sqlResultAll = await client.sqlService.execute('SELECT __key, this FROM cities', [], { returnRawResult: true }); - - process.stdout.write('OK.\n'); - process.stdout.write('--Results of SELECT __key, this FROM cities\n'); - process.stdout.write(sprintf('| %4s | %20s | %20s | %15s |\n', 'id', 'country', 'city', 'population')); - - // NodeJS client does lazy deserialization. In order to update schema table on the client, - // it's required to get a map value. - const cities = await client.getMap('cities'); - await cities.get(1); - - for await (const row of sqlResultAll) { - const id = row.getObject('__key'); - const cityDTO = row.getObject('this'); - process.stdout.write(sprintf('| %4d | %20s | %20s | %15d |\n', id, cityDTO.country, cityDTO.city, cityDTO.population)); - } - - process.stdout.write('\n!! Hint !! You can execute your SQL queries on your Viridian cluster over the management center. \n 1. Go to "Management Center" of your Hazelcast Viridian cluster. \n 2. Open the "SQL Browser". \n 3. Try to execute "SELECT * FROM cities".\n'); -} - -/////////////////////////////////////////////////////// - -(async () => { - - const client = await Client.newHazelcastClient({ - clusterName: '', - - // Connection details for cluster - network: { - hazelcastCloud: { - discoveryToken: '', - }, - - ssl: { - enabled: true, - sslOptions: { - ca: [fs.readFileSync(path.resolve(path.join(__dirname, 'ca.pem')))], - cert: [fs.readFileSync(path.resolve(path.join(__dirname, 'cert.pem')))], - key: [fs.readFileSync(path.resolve(path.join(__dirname, 'key.pem')))], - passphrase: '', - checkServerIdentity: () => null - }, - }, - }, - - // Register Compact Serializers - serialization: { - compact: { - serializers: [new CitySerializer()], - }, - defaultNumberType:"integer", - }, - - // Other environment propreties - properties: { - 'hazelcast.logging.level': 'WARN' // this property value is case-insensitive - }, - }); - - await createMapping(client); - await populateCities(client); - await fetchCities(client); - - await client.shutdown(); - -})().catch(err => { - process.stderr.write(`An error occured: ${err}\n`); -}); ----- - -The output of this code is given below: - -[source,bash] ----- -Connection Successful! -Creating the mapping...OK. -Inserting data...OK. -Fetching cities...OK. ---Results of 'SELECT __key, this FROM cities' -| id | country | city | population | -| 2 | United Kingdom | Manchester | 2770434 | -| 6 | Türkiye | Ankara | 5309690 | -| 1 | United Kingdom | London | 9540576 | -| 7 | Brazil | Sao Paulo | 22429800 | -| 4 | United States | Los Angeles | 3985520 | -| 5 | Türkiye | Istanbul | 15636243 | -| 3 | United States | New York | 19223191 | ----- - -NOTE: Ordering of the keys is NOT enforced and results may NOT correspond to insertion order. - -== Understanding the Hazelcast Map API - -A Hazelcast Map is a distributed key-value store, similar to Node map. You can store key-value pairs in a Hazelcast Map. - -In the following example, we will work with map entries where the keys are ids and the values are defined as a string representing a city name. - -[source,javascript] ----- -'use strict'; - -const { Client } = require('hazelcast-client'); -const fs = require('fs'); -const path = require('path'); -const process = require('process'); -const sprintf= require('sprintf-js').sprintf; - -#################################### - -(async () => { - - const client = await Client.newHazelcastClient({ - clusterName: '', - - // Connection details for cluster - network: { - hazelcastCloud: { - discoveryToken: '', - }, - - ssl: { - enabled: true, - sslOptions: { - ca: [fs.readFileSync(path.resolve(path.join(__dirname, 'ca.pem')))], - cert: [fs.readFileSync(path.resolve(path.join(__dirname, 'cert.pem')))], - key: [fs.readFileSync(path.resolve(path.join(__dirname, 'key.pem')))], - passphrase: '', - checkServerIdentity: () => null - }, - }, - }, - - // Register Compact Serializers - serialization: { - compact: { - serializers: [new CitySerializer()], - }, - defaultNumberType:"integer", - }, - - // Other environment propreties - properties: { - 'hazelcast.logging.level': 'WARN' // this property value is case-insensitive - }, - }); - - // - var citiesMap = await client.getMap('cities'); - - // Clear the map - await citiesMap.clear(); - - // Add some data - await citiesMap.put(1, 'London'); - await citiesMap.put(2, 'New York'); - await citiesMap.put(3, 'Tokyo'); - - // Output the data - const entries = await citiesMap.entrySet(); - - for (const [key, value] of entries) { - process.stdout.write(`${key} -> ${value}\n`); - } - - await client.shutdown(); - -})().catch(err => { - process.stderr.write(`An error occured: ${err}\n`); -}); ----- - -Following line returns a map proxy object for the `cities` map: - -[source, javascript] ----- -var citiesMap = await client.getMap('cities'); ----- - -If `cities` doesn't exist, it will be automatically created. All the clients connected to the same cluster will have access to the same map. - -With these lines, client adds data to the `cities` map. The first parameter is the key of the entry, the second one is the value. - -[source, python] ----- -await citiesMap.put(1, 'London'); -await citiesMap.put(2, 'New York'); -await citiesMap.put(3, 'Tokyo'); ----- - -Then, we get the data using the `entrySet()` method and iterate over the results. - -[source, javascript] ----- -const entries = await citiesMap.entrySet(); - -for (const [key, value] of entries) { - process.stdout.write(`${key} -> ${value}\n`); -} ----- - -Finally, `client.shutdown()` terminates our client and release its resources. - -The output of this code is given below: - -[source,bash] ----- -2 -> New York -1 -> London -3 -> Tokyo ----- - -NOTE: Ordering of the keys is NOT enforced and results may NOT correspond to entry order. - -== Adding a Listener to the Map - -You can add an entry listener using the `addEntryListener()` method available on the map proxy object. -This will allow you to listen to certain events that happen in the map across the cluster. - -The first argument to the `addEntryListener()` method is an object that is used to define listeners. -In this example, we register listeners for the `added`, `removed` and `updated` events. - -The second argument to the `addEntryListener()` method is `includeValue`. -This boolean parameter, if set to true, ensures the entry event contains the entry value. - -This enables your code to listen to map events of that particular map. - -[source, javascript] ----- -'use strict'; - -const { Client } = require('hazelcast-client'); -const fs = require('fs'); -const path = require('path'); -const process = require('process'); -const sprintf= require('sprintf-js').sprintf; - -#################################### - -(async () => { - - const client = await Client.newHazelcastClient({ - clusterName: '', - - // Connection details for cluster - network: { - hazelcastCloud: { - discoveryToken: '', - }, - - ssl: { - enabled: true, - sslOptions: { - ca: [fs.readFileSync(path.resolve(path.join(__dirname, 'ca.pem')))], - cert: [fs.readFileSync(path.resolve(path.join(__dirname, 'cert.pem')))], - key: [fs.readFileSync(path.resolve(path.join(__dirname, 'key.pem')))], - passphrase: '', - checkServerIdentity: () => null - }, - }, - }, - - // Register Compact Serializers - serialization: { - compact: { - serializers: [new CitySerializer()], - }, - defaultNumberType:"integer", - }, - - // Other environment propreties - properties: { - 'hazelcast.logging.level': 'WARN' // this property value is case-insensitive - }, - }); - - // - var citiesMap = await client.getMap('cities'); - - citiesMap.addEntryListener({ - added: (event) => { - process.stdout.write(`Entry added with key: ${event.key}, value: ${event.value}\n`) - }, - removed: (event) => { - process.stdout.write(`Entry removed with key: ${event.key}\n`); - }, - updated: (event) => { - process.stdout.write(`Entry updated with key: ${event.key}, old value: ${event.oldValue}, new value: ${event.value}\n`) - }, - }, undefined, true); - - // Clear the map - await citiesMap.clear(); - - // Add some data - await citiesMap.put(1, 'London'); - await citiesMap.put(2, 'New York'); - await citiesMap.put(3, 'Tokyo'); - - await citiesMap.remove(1); - await citiesMap.replace(2, 'Paris'); - - // Output the data - const entries = await citiesMap.entrySet(); - - for (const [key, value] of entries) { - process.stdout.write(`${key} -> ${value}\n`); - } - - await client.shutdown(); - -})().catch(err => { - process.stderr.write(`An error occured: ${err}\n`); -}); ----- - -First, the map is cleared, which will trigger removed events if there are some entries in the map. Then, entries are added, and they are logged. After that, we remove one of the entries and update the other one. Then, we log the entries again. - -The output is as follows. - -[source, bash] ----- -Entry added with key: 1, value: London -Entry added with key: 2, value: New York -Entry added with key: 3, value: Tokyo -Entry removed with key: 1 -Entry updated with key: 2, old value: New York, new value: Paris -2 -> Paris -3 -> Tokyo ----- - -The value of the first entry becomes "null" since it is removed. - -== Summary - -In this tutorial, you learned how to get started with the Hazelcast Node.js Client, connect to a Viridian instance and put data into a distributed map. - -== See Also - -There are a lot of things that you can do with the Node.js Client. For more, such as how you can query a map with predicates and SQL, -check out our https://github.com/hazelcast/hazelcast-nodejs-client[Node.js Client repository] and our http://hazelcast.github.io/hazelcast-nodejs-client/[Node.js API documentation] to better understand what is possible. - -If you have any questions, suggestions, or feedback please do not hesitate to reach out to us via https://slack.hazelcast.com/[Hazelcast Community Slack]. -Also, please take a look at https://github.com/hazelcast/hazelcast-nodejs-client/issues[the issue list] if you would like to contribute to the client. \ No newline at end of file diff --git a/docs/modules/tutorials/pages/python-client-getting-started.adoc b/docs/modules/tutorials/pages/python-client-getting-started.adoc deleted file mode 100644 index cd5afe18d..000000000 --- a/docs/modules/tutorials/pages/python-client-getting-started.adoc +++ /dev/null @@ -1,419 +0,0 @@ -= Getting Started with the Hazelcast Python Client -:description: This tutorial will get you started with the Hazelcast Python client and manipulate a map. - -== What You'll Learn - -{description} - -== Before you Begin - -* Python 3.6 or above -* https://hazelcast.com/products/viridian/[Hazelcast Viridian Cloud Account] -* A text editor or IDE - -== Start a Hazelcast Viridian Cloud Cluster - -1. Sign up for a Hazelcast Viridian Cloud account (free trial is available). -2. Log in to your Hazelcast Viridian Cloud account and start your trial by filling in the welcome questionnaire. -3. A Viridian cluster will be created automatically when you start your trial. -4. Press the Connect Cluster dialog and switch over to the Advanced setup tab for connection information needed below. -5. From the Advanced setup tab, download the keystore files and take note of your Cluster ID, Discovery Token and Password as you will need them later. - -== Setup a Hazelcast Client - -Create a new folder and navigate to it: - -[source] ----- -mkdir hazelcast-python-example -cd hazelcast-python-example ----- - -Download the Hazelcast Python Client library using pip: - -[source] ----- -python -m pip install hazelcast-python-client ----- - -Extract the keystore files you downloaded from Viridian into this directory. The files you need for this tutorial are: - -[source,bash] ----- -ca.pem -cert.pem -key.pem ----- - -== Understanding the Python Client - -The following section creates and starts a Hazelcast client with default configuration, connects to your Viridian cluster before shutting the client down at the end. - -Create a Python file named “example.py” and put the following code inside it: - -[source,python] ----- -import hazelcast -import os - -#################################### - -# Connect to your Hazelcast Cluster -client = hazelcast.HazelcastClient( - # Viridian Cluster Name and Token - cluster_name="", - cloud_discovery_token="", - - # configure SSL - ssl_enabled=True, - ssl_cafile=os.path.abspath("ca.pem"), - ssl_certfile=os.path.abspath("cert.pem"), - ssl_keyfile=os.path.abspath("key.pem"), - ssl_password="", -) - -# take actions -print("Welcome to your Hazelcast Viridian Cluster!") - -# Shutdown the client connection -client.shutdown() ----- - -To understand and use the client, review the https://hazelcast.readthedocs.io/en/stable/client.html#hazelcast.client.HazelcastClient[Python API documentation] to better understand what is possible. - -== Understanding the Hazelcast SQL API - -Hazelcast SQL API is a Calcite SQL based interface to allow you to interact with Hazelcast much like any other datastore. - -In the following example, we will create a map and insert into it, entries where the keys are ids and the values are defined as an object representing a city. - -[source,python] ----- -import hazelcast -from hazelcast import HazelcastClient -from hazelcast.serialization.api import CompactReader, CompactSerializer, CompactWriter -import os -import typing - -class City: - def __init__(self, country: str, city: str, population: int) -> None: - self.country = country - self.city = city - self.population = population - -class CitySerializer(CompactSerializer[City]): - def read(self, reader: CompactReader) -> City: - city = reader.read_string("city") - country = reader.read_string("country") - population = reader.read_int32("population") - return City(country, city, population) - - def write(self, writer: CompactWriter, obj: City) -> None: - writer.write_string("country", obj.country) - writer.write_string("city", obj.city) - writer.write_int32("population", obj.population) - - def get_type_name(self) -> str: - return "city" - - def get_class(self) -> typing.Type[City]: - return City - -def create_mapping(client: HazelcastClient) -> None: - print("Creating the mapping...", end="") - # See: https://docs.hazelcast.com/hazelcast/latest/sql/mapping-to-maps - mapping_query = """ - CREATE OR REPLACE MAPPING - cities ( - __key INT, - country VARCHAR, - city VARCHAR, - population INT) TYPE IMAP - OPTIONS ( - 'keyFormat' = 'int', - 'valueFormat' = 'compact', - 'valueCompactTypeName' = 'city') - """ - client.sql.execute(mapping_query).result() - print("OK.") - -def populate_cities(client: HazelcastClient) -> None: - print("Inserting data...", end="") - - insert_query = """ - INSERT INTO cities - (__key, city, country, population) VALUES - (1, 'London', 'United Kingdom', 9540576), - (2, 'Manchester', 'United Kingdom', 2770434), - (3, 'New York', 'United States', 19223191), - (4, 'Los Angeles', 'United States', 3985520), - (5, 'Istanbul', 'Türkiye', 15636243), - (6, 'Ankara', 'Türkiye', 5309690), - (7, 'Sao Paulo ', 'Brazil', 22429800) - """ - - try: - client.sql.execute('DELETE from cities').result() - client.sql.execute(insert_query).result() - print("OK.") - except Exception as e: - print(f"FAILED: {e!s}.") - -def fetch_cities(client: HazelcastClient) -> None: - print("Fetching cities...", end="") - result = client.sql.execute("SELECT __key, this FROM cities").result() - print("OK.") - - print("--Results of 'SELECT __key, this FROM cities'") - print(f"| {'id':>4} | {'country':<20} | {'city':<20} | {'population':<15} |") - - for row in result: - city = row["this"] - print( - f"| {row['__key']:>4} | {city.country:<20} | {city.city:<20} | {city.population:<15} |" - ) - -#################################### - -# Connect to your Hazelcast Cluster -client = hazelcast.HazelcastClient( - # Viridian Cluster Name and Token - cluster_name="", - cloud_discovery_token="", - - # configure SSL - ssl_enabled=True, - ssl_cafile=os.path.abspath("ca.pem"), - ssl_certfile=os.path.abspath("cert.pem"), - ssl_keyfile=os.path.abspath("key.pem"), - ssl_password="", - - # Register Compact serializer of City class - compact_serializers=[CitySerializer()], -) - -# Create a map on the cluster -create_mapping(client) - -# Add some data -populate_cities(client) - -# Output the data -fetch_cities(client) - -# Shutdown the client connection -client.shutdown() ----- - -The output of this code is given below: - -[source,bash] ----- -Creating the mapping...OK. -Inserting data...OK. -Fetching cities...OK. ---Results of 'SELECT __key, this FROM cities' -| id | country | city | population | -| 2 | United Kingdom | Manchester | 2770434 | -| 6 | Türkiye | Ankara | 5309690 | -| 1 | United Kingdom | London | 9540576 | -| 7 | Brazil | Sao Paulo | 22429800 | -| 4 | United States | Los Angeles | 3985520 | -| 5 | Türkiye | Istanbul | 15636243 | -| 3 | United States | New York | 19223191 | ----- - -NOTE: Ordering of the keys is NOT enforced and results may NOT correspond to insertion order. - -== Understanding the Hazelcast Map API - -A Hazelcast Map is a distributed key-value store, similar to Python dictionary. You can store key-value pairs in a Hazelcast Map. - -In the following example, we will work with map entries where the keys are ids and the values are defined as a string representing a city name. - -[source,python] ----- -import hazelcast -import os - -#################################### - -# Connect to your Hazelcast Cluster -client = hazelcast.HazelcastClient( - # Viridian Cluster Name and Token - cluster_name="", - cloud_discovery_token="", - - # configure SSL - ssl_enabled=True, - ssl_cafile=os.path.abspath("ca.pem"), - ssl_certfile=os.path.abspath("cert.pem"), - ssl_keyfile=os.path.abspath("key.pem"), - ssl_password="", -) - -# Create a map on the cluster -cities_map = client.get_map('cities').blocking() - -# Clear the map -cities_map.clear() - -# Add some data -cities_map.put(1, "London") -cities_map.put(2, "New York") -cities_map.put(3, "Tokyo") - -# Output the data -entries = cities_map.entry_set() - -for key, value in entries: - print(f"{key} -> {value}") - -# Shutdown the client connection -client.shutdown() ----- - -Following line returns a map proxy object for the `cities` map: - -[source, python] ----- -cities_map = client.get_map('cities').blocking() ----- - -If `cities` doesn't exist, it will be automatically created. All the clients connected to the same cluster will have access to the same map. - -You may wonder why we have used `blocking()` method over the `get_map()`. This returns a version of this proxy with only blocking -(sync) method calls, which is better for getting started. For async calls, please check our https://hazelcast.readthedocs.io/en/stable/#usage[API documentation]. - -With these lines, client adds data to the `cities` map. The first parameter is the key of the entry, the second one is the value. - -[source, python] ----- -cities_map.put(1, "London") -cities_map.put(2, "New York") -cities_map.put(3, "Tokyo") ----- - -Then, we get the data using the `entry_set()` method and iterate over the results. - -[source, python] ----- -entries = cities_map.entry_set() - -for key, value in entries: - print(f"{key} -> {value}") ----- - -Finally, `client.shutdown()` terminates our client and release its resources. - -The output of this code is given below: - -[source,bash] ----- -2 -> New York -1 -> London -3 -> Tokyo ----- - -NOTE: Ordering of the keys is NOT enforced and results may NOT correspond to entry order. - -== Adding a Listener to the Map - -You can add an entry listener using the `add_entry_listener()` method available on the map proxy object. -This will allow you to listen to certain events that happen in the map across the cluster. - -The first argument to the `add_entry_listener()` method is `includeValue`. -This boolean parameter, if set to true, ensures the entry event contains the entry value. - -The second argument to the `add_entry_listener()` method is an object that is used to define listeners. -In this example, we register listeners for the `added`, `removed` and `updated` events. - -This enables your code to listen to map events of that particular map. - -[source, python] ----- -import hazelcast -import os - -def entry_added(event): - print(f"Entry added with key: {event.key}, value: {event.value}") - -def entry_removed(event): - print(f"Entry removed with key: {event.key}") - -def entry_updated(event): - print(f"Entry updated with key: {event.key}, old value: {event.old_value}, new value: {event.value}") - -#################################### - -# Connect to your Hazelcast Cluster -client = hazelcast.HazelcastClient( - # Viridian Cluster Name and Token - cluster_name="", - cloud_discovery_token="", - - # configure SSL - ssl_enabled=True, - ssl_cafile=os.path.abspath("ca.pem"), - ssl_certfile=os.path.abspath("cert.pem"), - ssl_keyfile=os.path.abspath("key.pem"), - ssl_password="", -) - -# Create a map on the cluster -cities_map = client.get_map('cities').blocking() - -# Add listeners -cities_map.add_entry_listener( - include_value=True, added_func=entry_added, removed_func=entry_removed, updated_func=entry_updated -) - -# Clear the map -cities_map.clear() - -# Add some data -cities_map.set(1, "London") -cities_map.set(2, "New York") -cities_map.set(3, "Tokyo") - -cities_map.remove(1) -cities_map.replace(2, "Paris") - -# Output the data -entries = cities_map.entry_set() - -for key, value in entries: - print(f"{key} -> {value}") - -# Shutdown the client connection -client.shutdown() ----- - -First, the map is cleared, which will trigger removed events if there are some entries in the map. Then, entries are added, and they are logged. After that, we remove one of the entries and update the other one. Then, we log the entries again. - -The output is as follows. - -[source, bash] ----- -Entry added with key: 1, value: London -Entry added with key: 2, value: New York -Entry added with key: 3, value: Tokyo -Entry removed with key: 1 -Entry updated with key: 2, old value: New York, new value: Paris -2 -> Paris -3 -> Tokyo ----- - -The value of the first entry becomes `None` since it is removed. - -== Summary - -In this tutorial, you learned how to get started with the Hazelcast Python Client, connect to a Viridian instance and put data into a distributed map. - -== See Also - -There are a lot of things that you can do with the Python Client. For more, such as how you can query a map with predicates and SQL, -check out our https://github.com/hazelcast/hazelcast-python-client[Python Client repository] and our https://hazelcast.readthedocs.io/en/stable/client.html#hazelcast.client.HazelcastClient[Python API documentation] to better understand what is possible. - -If you have any questions, suggestions, or feedback please do not hesitate to reach out to us via https://slack.hazelcast.com/[Hazelcast Community Slack]. -Also, please take a look at https://github.com/hazelcast/hazelcast-python-client/issues[the issue list] if you would like to contribute to the client. diff --git a/docs/modules/tutorials/pages/stream-from-kafka-kerberos.adoc b/docs/modules/tutorials/pages/stream-from-kafka-kerberos.adoc deleted file mode 100644 index b85e36d81..000000000 --- a/docs/modules/tutorials/pages/stream-from-kafka-kerberos.adoc +++ /dev/null @@ -1,158 +0,0 @@ -= Connect Hazelcast to Kafka Clusters Secured with Kerberos -:description: Learn how to connect Hazelcast Jet pipelines to Kafka clusters that are secured with Kerberos authentication. - -{description} - -[.interactive-button] -link:https://gitpod.io/#https://github.com/hazelcast-guides/kafka-kerberos[Try it in your browser,window=_blank] - -== Context - -When Kafka brokers are secured with Kerberos authentication, your Hazelcast cluster must acquire session keys from the Kerberos server before the Hazelcast cluster can communicate with the Kafka brokers. - -In this example, you'll learn how to configure the Hazelcast Kafka connector to connect to a Kafka broker that's secured with Kerberos authentication. - -== Before you Begin - -Before starting this tutorial, make sure that you have the following prerequisites: - -* link:https://docs.docker.com/compose/install/[Docker Compose] -* link:https://git-scm.com/book/en/v2/Getting-Started-Installing-Git[Git] -* xref:hazelcast:deploy:versioning-compatibility.adoc[JDK 8 - 11] -* link:https://maven.apache.org/download.cgi[Maven] -* Knowledge of link:https://en.wikipedia.org/wiki/Kerberos_(protocol)[Kerberos] -* Knowledge of link:https://en.wikipedia.org/wiki/Apache_Kafka[Kafka] - -== Step 1. Clone the Project - -To set up the project, you need to download the code from GitHub. - -Clone the GitHub repository. - -[tabs] -==== -HTTPS:: -+ --- -```bash -git clone https://github.com/hazelcast-guides/kafka-kerberos.git -cd kafka-kerberos -``` --- -SSH:: -+ --- -```bash -git clone git@github.com:hazelcast-guides/kafka-kerberos.git -cd kafka-kerberos -``` --- -==== - -== Step 2. Start the Docker Containers - -In this step, you'll use Docker Compose to start all the Docker containers, including a Kafka broker, Kerberos server, Hazelcast Platform, and Management Center. - -```bash -docker compose up -d -``` - -The Docker containers are running in detatched mode. You can see that they are running, using the following command: - -``` -docker ps -``` - -To see the logs of your Hazelcast member, use the following command: - -``` -docker logs hazelcast -``` - -You should see that you have a single member running in the cluster. - -``` -Members {size:1, ver:1} [ - Member [172.19.0.4]:5701 - 15116025-342b-43c0-83f7-a2a90f0281ce this -] -``` - -== Step 3. Create a Kafka Topic - -To create a Kafka topic, you'll use the `kafka-console-producer` script that's built into the Kafka broker. - -Create the `orders` topic and add some records to it. - -```bash -docker exec -i broker kafka-console-producer --broker-list broker:9092 --topic orders < orders.jsonl --producer.config /etc/kafka/kafka-client.properties -``` - -The `kafka-client.properties` file contains the Kafka client configuration that allows Kerberos to authenticate Kafka clients. The Kafka clients assume the `jduke@KERBEROS.EXAMPLE` SPN (service principal name), which is registered on the Kerberos server. - -== Step 4. Connect Hazelcast to the Kafka Broker - -Now that your Kafka topic has some records, you can configure the Kafka connector in Hazelcast to consume those records. In this step, you'll create a Jet job that reads from the Kafka topic and writes the data to a Hazelcast map called `sink_orders`. This Kafka connector is configured to assume the same SPN as the producer in the previous step. - -. Change into the `jet-pipeline` directory. - -. Package the Java file into a JAR. -+ -```bash -mvn package -``` - -. Submit the JAR to your Hazelcast member. Replace the `$PATH_TO_PROJECT` placeholder with the absolute path to the `kafka-kerberos` directory. -+ -```bash -docker run -it --network kafka-kerberos_default -v $PATH_TO_PROJECT/jet-pipeline/target:/jars --rm hazelcast/hazelcast:5.1.4 hz-cli -t hazelcast:5701 submit -c com.example.hazelcast.jet.kafka.KafkaSourceWithClientServerHazelcast /jars/jet-kafka-1.0.0.jar -``` - -You should see the following in the console: - -``` -Submitting JAR '/jars/jet-kafka-1.0.0.jar' with arguments [] -Orders added to map -=================== -``` - -Your Hazelcast cluster connects to the Kerberos server, acquires a session key and reads records from the `orders` topic. Your Hazelcast cluster now contains a map called `sink_orders` that contains the orders. - -== Step 5. Verify that the Connection Succeeded - -In this step, you'll verify that the Kerberos server authenticated Hazelcast and the Kafka broker allowed the Hazelcast Kafka connector to read from the `orders` topic. - -. Go to `localhost:8080` and enable dev mode in Management Center. - -. Open the SQL Browser. - -. In the *select a map* dropdown, select *sink_orders (No SQL Mapping)* to auto-generate the `CREATE MAPPING` command. - -. Click *Execute Query* - -. Delete the previous command from the SQL editor and enter the following: -+ -```sql -SELECT * FROM sink_orders; -``` - -. Click *Execute Query*. - -The `sink_orders` map contains all the records in the `orders` topic. - -== Related Resources - -Kafka and Kerberos: - -- For details about how to configure Kafka clients with Kerberos, see the link:https://docs.confluent.io/platform/current/kafka/authentication_sasl/authentication_sasl_gssapi.html#clients[Confluent documentation]. - -- link:https://docs.confluent.io/platform/current/kafka/authentication_sasl/authentication_sasl_gssapi.html#configuring-gssapi[Configuring GSSAPI] - -- link:https://developer.confluent.io/learn-kafka/security/authentication-ssl-and-sasl-ssl/[Kafka security course] - -Hazelcast: - -- xref:hazelcast:sql:sql-overview.adoc[] -- xref:hazelcast:sql:mapping-to-kafka.adoc[] -- xref:hazelcast:sql:mapping-to-maps.adoc[] -- xref:hazelcast:sql:querying-streams.adoc[] - diff --git a/docs/modules/tutorials/pages/tutorials-index.adoc b/docs/modules/tutorials/pages/tutorials-index.adoc deleted file mode 100644 index fa953a59a..000000000 --- a/docs/modules/tutorials/pages/tutorials-index.adoc +++ /dev/null @@ -1,17 +0,0 @@ -= Tutorials - - - -== Hazelcast Platform -* xref:tutorials:kubernetes.adoc[] -* xref:tutorials:java-client-getting-started.adoc[] -* xref:tutorials:csharp-client-getting-started.adoc[] -* xref:tutorials:go-client-getting-started.adoc[] -* xref:tutorials:nodejs-client-getting-started.adoc[] -* xref:tutorials:python-client-getting-started.adoc[] -* xref:tutorials:cpsubsystem.adoc[] -* xref:tutorials:join-two-streams.adoc[] -* xref:tutorials:stream-from-kafka-kerberos.adoc[] - -== Hazelcast Cloud -* xref:tutorials:hazelcast-platform-operator-expose-externally.adoc[] \ No newline at end of file