Hash Import (HIMPORT)
Overview
The HIMPORT command (Redis 8.10 and later) is a fast way to create many hashes
that share a common set of field names — for example, importing a batch of records where every
record has the same columns. Rather than sending the field names again for every hash (as a
series of HSET calls would), the field names are declared once per connection and each hash
then supplies only its values, positionally matched to those fields.
On the wire this is a connection-local container command: HIMPORT PREPARE registers a named
field-set (the ordered field names) on the current connection, HIMPORT SET creates one hash
from a row of values against that field-set, and HIMPORT DISCARD releases it. A field-set
lives only on the connection that prepared it and disappears when that connection is reset or
closed.
Depending on the client, commands travel over a single direct connection (Jedis) or over a
pool of connections (RedisClient, RedisClusterClient) — with a pool, each himportSet can
end up on an arbitrary connection. Rather than expose the raw connection-local commands — which
are not safe to drive by hand across pooled connections — Jedis exposes a reusable HashImport
field-set template plus a per-row himportSet command, and manages the lifecycle: the
HIMPORT PREPARE is injected automatically the first time a template is seen on each
connection, a redirect to another cluster node simply re-prepares on demand, and closing the
template schedules HIMPORT DISCARD on every connection it touched. You never manage
PREPARE/SET/DISCARD ordering or connection pinning yourself.
HashImportandhimportSetare marked@Experimental: the API may change in a future release. They require Redis 8.10 or later.
Usage
Create a field-set template once (declaring the shared field names, in order), then import each hash by supplying its key and its values positionally against those fields:
import redis.clients.jedis.HashImport;
import redis.clients.jedis.RedisClient;
RedisClient client = RedisClient.create("redis://localhost:6379");
// declare the field names shared by every hash we are importing; reusable and safe to share
try (HashImport fields = HashImport.of("name", "email", "age")) {
// import as many hashes as you like — one command per hash, so the total is unbounded
client.himportSet("user:1", fields, "alice", "a@example.com", "30");
client.himportSet("user:2", fields, "bob", "b@example.com", "25");
client.himportSet("user:3", fields, "carol", "c@example.com", "42");
}
After these complete, user:1, user:2 and user:3 each exist as an ordinary hash with the
name, email and age fields set to their respective values — readable with HGETALL,
HGET and every other hash command. Any existing hash at an imported key is replaced.
Closing the template (try-with-resources or close()) schedules a best-effort
HIMPORT DISCARD to release the server-side state; it is optional (the state also dies with
the connection) but good hygiene for long-lived connections. A closed template must not be used
again.
Pipelining
For large imports, combine the template with a pipeline to avoid a round trip per hash. The
HIMPORT PREPARE is buffered automatically ahead of the first use on the pipeline's
connection, and its reply is internal — syncAndReturnAll() returns exactly one result per
command you issued:
import redis.clients.jedis.HashImport;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.RedisClient;
import redis.clients.jedis.Response;
RedisClient client = RedisClient.create("redis://localhost:6379");
try (HashImport fields = HashImport.of("name", "email", "age");
Pipeline pipeline = client.pipelined()) {
Response<String> u1 = pipeline.himportSet("user:1", fields, "alice", "a@example.com", "30");
Response<String> u2 = pipeline.himportSet("user:2", fields, "bob", "b@example.com", "25");
Response<String> u3 = pipeline.himportSet("user:3", fields, "carol", "c@example.com", "42");
pipeline.sync();
// each returns "OK"
u1.get();
u2.get();
u3.get();
}
Cluster
himportSet works unchanged with RedisClusterClient: each key routes to its slot, and the
template re-prepares per node as needed.
Limitations
- Transactions:
himportSetis not supported insideMULTI/EXEC— the connection-localPREPAREcannot be staged in a transaction. Attempting it throwsUnsupportedOperationException. - Cluster pipelines: not supported. Use the standard (non-pipelined)
himportSetonRedisClusterClientinstead. - A template dropped without
close()leaves its server-side state on the connections it touched until those connections are recycled.