kevy4.0

セカンダリインデックス(IDX.* / idx_*

kevyは、キー空間のプレフィックスドメインに対して宣言型のセカンダリインデックスを維持できます。プレフィックス配下のハッシュキーが1つの「行」であり、宣言された1つのハッシュフィールドがインデックス対象の値です。インデックスはすべての書き込みと同期して維持され(構成上の派生物——インデックスがデータからドリフトすることは原理的にあり得ず、IDX.VERIFYがそれを反証可能にします)、カーソルページング、2インデックスの合成、任意のフィールドhydrationとともにクエリできます。

IDX.CREATE idx_age ON PREFIX user: FIELD age TYPE i64 KIND range
HSET user:42 age 31 name "……"
IDX.QUERY idx_age RANGE 18 30 LIMIT 100 FIELDS name

宣言する

IDX.CREATE <name> ON PREFIX <p> FIELD <f> TYPE i64|f64|str KIND range|unique [MAXMEM <bytes>]

クエリする

一意性はフェンスであって、ロックではない

uniqueインデックスは書き込みをブロックしません。書き込み時にグローバルな一意性を強制すれば、シャードをまたぐ書き込みを直列化することになるからです。代わりに、重複は数えられ(VERIFY/LISTのduplicates)、EQ読み出しが複数ヒットする形で可視になります。硬い一意性が必要なら、クラスタモードで{hashtag}プレフィックスによりドメインを1シャードに固定するか、MULTI/WATCHのもとでcheck-then-writeしてください。

組み込み

同じエンジンを型付きAPIで使います。idx_create / idx_drop / idx_query / idx_count / idx_stats / idx_list(値はIndexValue、カーソルはIndexCursor)。FIELDSのhydrationはありません——プロセス内にいるのですから、フィールドはhgetで読んでください。idx_createは同期的にビルドし、インデックスが提供可能になった時点で返ります。

整合性とコストモデル

集約kind(KIND agg)——書き込み時GROUP BY

IDX.CREATE ord_amt ON PREFIX ord: FIELD amount TYPE i64 KIND agg GROUPBY status
IDX.QUERY ord_amt GROUP paid                      → [count, sum, min, max, avg]
IDX.QUERY ord_amt GROUPS BY sum LIMIT 100         → ranked [group, count, sum, min, max]

SELECT g, COUNT(*), SUM(v) … GROUP BY gに対するエンジンの答えです。集約は書き込みパスの中で維持されます(宣言されたアクセスパスであって、クエリ時の行スキャンでは決してありません)。min/maxはグループごとの値の多重集合により、削除のもとでも正確なままです。sumはf64で累積されます(精度の限界は文書化済み)。値の型強制に失敗した行、あるいはグループフィールドが欠けている行は除外され、数えられます(VERIFY)。シャードをまたぐマージは正確です。countとsumは足し合わされ、極値は取り合わされます。GROUPSはcount/sum/maxの降順、またはminの昇順でランクづけし、LIMITは1000以下です。

HAVINGなし、集約式なし、近似スケッチなし——それはクエリ言語への坂道です。GROUPSの結果はアプリ側でフィルタしてください。

組み込みではidx_create_agg(name, prefix, field, ty, group_by) / idx_group(name, g) / idx_groups(name, by, limit)です。

メモリは概算でgroups × (gkey+64) + distinct_values × 18 + rows × (key+10)です(定数は実測RSSに対して較正済み)。GROUP p99 < 1ms @ 1M×10kグループ、GROUPSのtop-100 < 5ms、書き込み税 < 10%とあわせて、bench/agggate.shが実RSSに対してゲートします。