Get started with the Hazelcast Python Client

Overview

This tutorial will get you started with the Hazelcast Python client and show you how to manipulate a map.

This tutorial will take approximately 5-10 minutes to complete.

Prerequisites

Before you begin, make sure you have the following:

Start a Hazelcast Cloud Cluster

  1. Sign up for a Hazelcast Cloud account (free trial is available).

  2. Log in to your Hazelcast Cloud account and start your trial by filling in the welcome questionnaire.

  3. A cluster is 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.

Set up a Hazelcast Client

Create a new folder and navigate to it:

mkdir hazelcast-python-example
cd hazelcast-python-example

Download the Hazelcast Python Client library using pip:

python -m pip install hazelcast-python-client

Extract the keystore files you downloaded into this directory. The files you need for this tutorial are:

ca.pem
cert.pem
key.pem

Understand the Python Client

The following section creates and starts a Hazelcast client with default configuration, and connects to your cluster before finally shutting down the client.

Create a Python file named “example.py” and put the following code inside it:

import hazelcast
import os

####################################

# Connect to your Hazelcast Cluster
client = hazelcast.HazelcastClient(
    # Cluster Name and Token
    cluster_name="<YOUR_CLUSTER_ID>",
    cloud_discovery_token="<YOUR_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="<YOUR_CERTIFICATE_PASSWORD>",
)

# take actions
print("Welcome to your Hazelcast Cluster!")

# Shutdown the client connection
client.shutdown()

To understand and use the client, review the Python API documentation to discover what is possible.

Understand 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 entries into it where the keys are ids and the values are defined as an object representing a city.

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(
    # Cluster Name and Token
    cluster_name="<YOUR_CLUSTER_ID>",
    cloud_discovery_token="<YOUR_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="<YOUR_CERTIFICATE_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:

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        |
Ordering of the keys is NOT enforced and results may NOT correspond to insertion order.

Understand 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.

import hazelcast
import os

####################################

# Connect to your Hazelcast Cluster
client = hazelcast.HazelcastClient(
    # Cluster Name and Token
    cluster_name="<YOUR_CLUSTER_ID>",
    cloud_discovery_token="<YOUR_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="<YOUR_CERTIFICATE_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()

The following line returns a map proxy object for the cities map:

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 API documentation.

With these lines, the client adds data to the cities map. The first parameter is the key of the entry, the second one is the value.

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.

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:

2 -> New York
1 -> London
3 -> Tokyo
Ordering of the keys is NOT enforced and results may NOT correspond to entry order.

Add 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.

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(
    # Cluster Name and Token
    cluster_name="<YOUR_CLUSTER_ID>",
    cloud_discovery_token="<YOUR_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="<YOUR_CERTIFICATE_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.

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 an instance and put data into a distributed map.

Next steps

There are many things you can do with the Python Client. For more information, such as how you can query a map with predicates and SQL, check out the Python Client repository and the Python API documentation to better understand what’s possible.

If you have any questions, suggestions, or feedback, reach out to us via Hazelcast Community Slack. To contribute to the client, take a look at the issue list.