Interactive Queries (IQ) expose the results of Kafka Streams stateful operations by querying their state stores directly. A dashboard or sibling application can read current aggregation or reduction results as processing occurs, rather than requiring the stream processor to first export those results to a relational database. IQ therefore adds a serving path for live materialized views; it does not make relational databases unnecessary in every application. section 13.0 section 13.1
A queryable store needs an explicit name. Supply that name through `Materialized.as(...)` or a store supplier when building the aggregation. Kafka Streams may create an unnamed store, but that store is not eligible for IQ. Naming stateful resources also helps preserve topology compatibility when the topology changes. section 13.2 section 7.4.5
Listing 13.1 Naming state stores to enable them for querying
Materialized.<String, LoanAppRollup>as(
Stores.inMemoryKeyValueStore(loanAppStoreName)) #1
.withKeySerde(stringSerde)
.withValueSerde(loanAppRollupSerde))
Materialized.<String, LoanAppRollup>as(
loanAppStoreName) #2
.withKeySerde(stringSerde)
.withValueSerde(loanAppRollupSerde))
Materialized.with(stringSerde, loanAppRollupSerde) #3
Use `Materialized` to give an aggregation store a stable, queryable name; either an in-memory supplier or the default persistent store can be named. section 13.2
IQ is local first. Kafka Streams creates state stores per task, and tasks correspond to partitions. In a multi-instance application, each instance owns only a subset of partitions, so its local stores contain only part of the total state. Configure `application.server` with a unique host and port on every instance so clients can locate the instance responsible for a query. section 13.2
A key query can follow this routing flow:
- Ask `queryMetadataForKey` for `KeyQueryMetadata`, using the store name, key, and key serializer. section 13.2.1
- Compare the returned active `HostInfo` with the current instance's host and port. section 13.2.1
- When local, build a `KeyQuery` and `StateQueryRequest` for the assigned partition, execute `kafkaStreams.query(...)`, and extract the partition result. section 13.2.1
- When remote, send the same request path to the target host; a failed active-host request can fall back to a standby host. section 13.2.1
Serving loan approval rollups over HTTP
A loan-processing topology aggregates approval results by loan category into a named store. A Spring Boot application enables its embedded servlet web server and maps `/loan-app-iq/loantype/{category}` in a `@RestController`. The controller finds metadata for the category key, queries locally when it owns that partition, otherwise forwards the request to the owning instance, then returns the rollup as JSON. An HTML page can repeatedly call the REST API to display current results. section 13.2.1 section 13.3
Range-style queries differ from a single-key lookup because relevant values may span partitions and instances. Obtain the instances serving the store, determine their partitions, issue a range query to each, and combine the returned results. Query responses should also represent errors, since metadata lookup or a remote request can fail. section 13.2.1
