缓存KV存储消息队列流处理后端【免费下载链接】hazelcastHazelcast is a unified real-time data platform combining stream processing with a fast data store, allowing customers to act instantly on>项目地址https://gitcode.com/gh_mirrors/ha/hazelcast点击查看免费下载导读本文基于 Hazelcast 官方设计文档 docs/design/sql/12-create-index.md系统讲解 Hazelcast SQL 引擎中CREATE INDEX语句的设计与实现。该能力自 Hazelcast 5.1 引入用于通过 SQL 为 IMap 动态创建索引是 SQL 引擎动态配置能力的重要补充。读完本文你将掌握CREATE INDEX的完整语法、三种索引类型SORTED / HASH / BITMAP及 BITMAP 专属选项的用法理解索引名称作用域、与 SQL 映射Mapping的关系、权限模型等设计约束并能结合源码理解其从 SQL 解析到IMap#addIndex调用的完整链路。一、背景与动机IMap分布式 Map是 Hazelcast 最核心的数据结构其查询性能高度依赖索引。在 Hazelcast 5.1 之前索引只能通过编程式配置IndexConfig或 XML/YAML 配置在成员端定义Hazelcast SQL 引擎的推出使得用户希望通过 SQL 直接管理索引从而提升 SQL 引擎的动态配置能力、丰富 SQL 语法。本设计文档正是为了实现通过 SQL 为 IMap 创建索引这一目标而编写对应的底层实现是IMap#addIndex(IndexConfig)方法的调用。需要特别说明的是当前版本只支持索引的创建尚不支持索引删除。虽然文档中给出了DROP INDEX的语法设计但从源码实现看该语句目前会在执行阶段抛出DROP INDEX is not supported.错误见 SqlPlanImpl.java 中DropIndexPlan.execute的实现属于尚未落地的语法占位。二、SQL 语法总览设计文档给出了CREATE INDEX的完整语法同时给出了计划中的DROP INDEX语法CREATE INDEX [ IF NOT EXISTS ] index_name ON imap_name ( attribute_name [, ...] ) [ TYPE ( SORTED | HASH | BITMAP ) ] [ OPTIONS ( option_name option_value [, ...] ) ]DROP INDEX [ IF EXISTS ] index_name ON imap_name从语法结构上可以看出三个关键设计点必须使用ON imap_name指明索引挂在哪个 IMap 上。这是因为索引名index_name的作用域是map 级别同一个集群中不同 IMap 上的索引可以同名这也是DROP INDEX语句也保留ON子句的原因。索引直接绑定 IMap而非绑定 SQL Mapping。CREATE INDEX语句不接受 schema 限定创建的索引也不会成为 catalog 中的独立对象。索引不会出现在information_schema中当前版本。对应的语法解析定义位于 parserImpls.ftlHazelcast SQL 使用 Calcite 的 FreeMarker 语法模板生成解析器其中SqlCreateIndex与SqlDropIndex两个规则分别处理这两类语句构建出SqlCreateIndex/SqlDropIndex语法节点。三、语句参数详解1.IF NOT EXISTS当指定该子句后如果addIndex因索引已存在而抛出异常该异常会被忽略语句静默成功。注意从 PlanExecutor.java 的实现看IF NOT EXISTS的实现方式是忽略已存在异常——addIndex()调用本身在索引同名已存在时即使配置不同也不会做任何事。而未指定IF NOT EXISTS时执行端会做一次简单的存在性检查如果同名索引已在getGlobalIndexRegistry()中注册则抛出Cant create index: index ... already exists错误。这种检查并非原子操作因此两个客户端并发创建同名索引时理论上可能都成功——源码注释明确承认了这一限制并指出 IMDG 中没有原子的创建索引操作难以完全规避。2. 索引列attribute_nameattribute_name是IMDG 索引 API 所定义的属性名它可能与 SQL 中的列名并不完全一致因为索引不感知 SQL 映射Mapping的存在。例如如果属性引用的是数组索引会把数组中的每个元素作为独立的索引条目全部指向包含该数组的 entry而在 SQL 中数组类型目前完全不支持。复合索引Composite Index同样受支持——在括号内列出多个属性即可。3. 索引类型TYPEIMDG 支持的三种索引类型全部可用于CREATE INDEX类型说明SORTED有序索引支持范围查询与排序默认类型对应IndexConfig.DEFAULT_TYPEHASH哈希索引适用于等值查询BITMAP位图索引适用于低基数cardinality属性的快速过滤支持额外选项从 SqlCreateIndex.java 的getIndexType()方法可以看到类型字符串会转为小写后匹配sorted/hash/bitmap三个关键字其他任何值都会抛出错误Cant create index: wrong index type. Only HASH, SORTED and BITMAP types are supported.⚠️重要限制SQL 引擎不支持 BITMAP 索引的扫描scan但支持 BITMAP 索引的创建。也就是说你可以通过 SQL 为低基数字段建立 BITMAP 索引供其他查询路径/谓词 API 使用但 SQL 查询本身当前无法利用该 BITMAP 索引执行扫描。4. OPTIONS 选项选项options仅对 BITMAP 索引可用因为位图索引拥有额外的BitmapIndexConfig。支持的选项只有两个unique_key指定位图索引的唯一键unique key用于区分位图条目。若未指定默认取__key即KEY_ATTRIBUTE_NAME查询常量对应 entry 的 key。unique_key_transformation指定唯一键的转换方式取值对应 IMDG 的UniqueKeyTransformation枚举。测试用例中使用的值为OBJECT见 SqlCreateIndexTest.java 中的OPTIONS (unique_key __key , unique_key_transformation OBJECT)示例。指定未知选项会抛出错误。此外校验逻辑还包括如果索引类型不是 BITMAP 却提供了 options抛出不支持错误列名重复如(this, this)抛错同一选项名重复指定抛错OR REPLACE子句不被支持会抛出not supported(OR REPLACE, CREATE INDEX)错误。执行端PlanExecutor.java 的execute(CreateIndexPlan)会把这两个选项组装进BitmapIndexOptions先取用户显式配置的值缺省时unique_key回退到__key、unique_key_transformation回退到默认常量DEFAULT_UNIQUE_KEY_TRANSFORMATION最后通过UniqueKeyTransformation.fromName(...)完成枚举转换并挂到IndexConfig上。四、底层实现链路从 SQL 到 IMap 索引CREATE INDEX语句的完整执行链路如下对应源码路径逐级递进语法解析Calcite 解析器根据 parserImpls.ftl 中定义的SqlCreateIndex规则将 SQL 文本解析为SqlCreateIndex语法节点语法校验SqlCreateIndex.java 的validate()方法完成类型、选项、列名去重等校验并通过columns()/type()/options()/mapName()/indexName()等访问器暴露解析结果计划生成CalciteSqlOptimizerImpl.java 将SqlCreateIndex节点转换为CreateIndexPlan该计划不可缓存且执行时不接受参数、不支持超时计划执行PlanExecutor.java 的execute(CreateIndexPlan)完成最终落地核心步骤为通过hazelcastInstance.getMap(plan.mapName())获取 IMap 的MapContainer校验全局索引前提若mapContainer.shouldUseGlobalIndex()为 false即分区索引抛出INDEX_INVALID错误提示必须开启集群属性ClusterProperty.GLOBAL_HD_INDEX_ENABLEDhazelcast.global.hd.index.enabled一类属性才能通过 SQL 创建索引因为SQL 目前无法使用分区索引构建IndexConfignew IndexConfig(indexType, attributes).setName(indexName)BITMAP 类型时再附加BitmapIndexOptions调用IMap#addIndex(indexConfig)完成索引创建返回更新计数结果0。SQL 文本 → Calcite 解析parserImpls.ftl → SqlCreateIndex → 语法校验SqlCreateIndex#validate → 计划生成CalciteSqlOptimizerImpl → CreateIndexPlan → 计划执行PlanExecutor#execute → IMap#addIndex(IndexConfig)全局索引要求务必注意这是源码实现中最容易踩坑的约束通过 SQL 创建的索引必须是全局索引global index。默认配置下分区存储使用分区索引此时 SQLCREATE INDEX会直接失败报错提示中明确给出了排障方向——将GLOBAL_HD_INDEX_ENABLED集群属性设为true。在设计文档的语法层面没有体现这一约束但源码执行阶段强制执行。五、权限模型索引创建受ACTION_INDEX权限保护该权限作用于目标 IMap。从实现看CreateIndexPlan在执行前会通过安全上下文校验对应权限相应地DropIndexPlan的checkPermissions使用ACTION_DESTROY权限虽然 DROP 尚未真正实现。这意味着在启用安全Security的集群中用户必须被授予目标 IMap 上的相应权限才能执行CREATE INDEX。六、向后兼容性该特性只是对既有索引实现IMap 索引 API的一层 SQL 封装因此老版本客户端可以无缝使用。在混合版本集群中如果命令落在 5.0 成员上会抛出语法异常类似unexpected token: INDEX跟在CREATE关键字之后如果命令落在 5.1 成员上则即使集群中还有其他 5.0 成员它们也能正常使用该特性。无需针对版本做特殊处理。七、测试验证设计文档指出该特性以单元测试与浸泡测试soak tests覆盖即可。仓库中对应的测试文件为 SqlCreateIndexTest.java其中的关键测试场景直接印证了文档中的各条语义HASH 索引CREATE INDEX IF NOT EXISTS idx ON map (this) TYPE HASH创建后查询计划从未使用索引变为使用索引checkPlan(true, ...)SORTED 索引默认类型验证CREATE INDEX ... (this) TYPE SORTED同样改变查询计划BITMAP 基础创建CREATE INDEX IF NOT EXISTS idx ON map (__key) TYPE BITMAP创建成功后可在getGlobalIndexRegistry().getIndex(indexName)中查到BITMAP 带选项创建OPTIONS (unique_key __key , unique_key_transformation OBJECT)正常执行空 map 上创建索引创建不依赖已有数据默认类型不写 TYPECREATE INDEX IF NOT EXISTS idx ON map (this)使用默认 SORTED重复列名(this, this)抛出包含specified more than once的错误。八、未来演进方向设计文档还规划了三个未来方向目前均未实现可作为理解设计意图的参考1. 面向不同连接器的索引预期未来需要为ReplicatedMap等结构创建索引为此计划在ON之后增加可选的CONNECTOR子句CREATE INDEX index_name ON imap_name ( attribute_name, ...) [ CONNECTOR IMap ]CONNECTOR子句为可选IMap为默认连接器该子句未来也需同步加入DROP INDEX命令。2. 函数式索引Function-Based IndexesSQL 世界中函数式索引FBI是指索引值为 SQL 表达式计算结果的情况典型场景是大小写不敏感搜索索引UPPER(column)查询用WHERE UPPER(column)UPPER(?)。IMap 本身不支持 FBI但支持派生属性derived attribute可通过两种方式近似实现对 Java 序列化DataSerializable对象用户可添加返回派生值的 getter后续查询用派生字段代替原始字段进行搜索指定提取器extractor适用于所有序列化类型包括 Portable 与 Compact 序列化。SQL 引擎已支持第一种方式自定义 getter 已被映射为字段计划进一步映射 extractor 并允许这些列出现在查询中时使用索引。但要注意这并非真正的 FBI——索引定义与查询中都不会出现 SQL 表达式。3. 基于 Mapping 的索引被否决的方案设计过程中曾考虑基于映射名创建索引但最终被否决理由包括索引生命周期不清晰索引为映射而创建但映射被删除后索引却依然存在映射与索引之间会产生依赖而 catalog 存储缺少事务支持无法正确实现例如字段类型从 INT 改为 VARCHAR 时索引需要重建或需要阻止映射的变更为映射创建的索引无法被同一 IMap 的其他映射使用也无法被旧的谓词 API 使用会模糊映射只是指向实际数据对象的轻量引用这一设计理念。如果未来实现基于映射的索引可能采用的语法形式有CREATE INDEX index_name ON MAPPING mapping_name ... CREATE INDEX index_name ON mapping_name(...) CONNECTOR mapping ... CREATE MAPPING INDEX index_name ON mapping_name ...九、快速上手示例综合以上语法与源码约束给出一个可在 Hazelcast 5.1 集群中直接执行的完整示例序列-- 1. 准备数据已有 map 的前提下 -- 需确保集群开启了全局索引hazelcast.global.hd.index.enabledtrue -- 2. 创建默认类型的 SORTED 索引 CREATE INDEX IF NOT EXISTS idx_name ON my_map (name); -- 3. 显式指定 HASH 索引 CREATE INDEX IF NOT EXISTS idx_hash ON my_map (id) TYPE HASH; -- 4. 创建复合 SORTED 索引 CREATE INDEX IF NOT EXISTS idx_composite ON my_map (last_name, first_name) TYPE SORTED; -- 5. 创建带选项的 BITMAP 索引 CREATE INDEX IF NOT EXISTS idx_bitmap ON my_map (__key) TYPE BITMAP OPTIONS (unique_key __key, unique_key_transformation OBJECT);执行上述语句后可通过getGlobalIndexRegistry().getIndex(index_name)成员端程序化方式或直接运行针对性查询计划来验证索引已生效。注意BITMAP 索引虽然可创建但当前 SQL 查询无法利用其进行扫描。参考链接设计文档docs/design/sql/12-create-index.md语法解析Calcite FMPP 模板parserImpls.ftl语法节点与校验SqlCreateIndex.java执行实现PlanExecutor.java执行计划定义SqlPlanImpl.java测试用例SqlCreateIndexTest.java赞分享缓存KV存储消息队列流处理后端【免费下载链接】hazelcastHazelcast is a unified real-time data platform combining stream processing with a fast data store, allowing customers to act instantly on>项目地址https://gitcode.com/gh_mirrors/ha/hazelcast点击查看免费下载相关推荐Flink Hive 方言 LOAD DATA 语句完全指南语法、参数与源码实现剖析Flink Hive 方言 LOAD DATA 语句完全指南语法、参数与源码实现剖析 LOAD DATA 是 Flink Hive 方言中用于将用户指定目录或后端大数据流处理批处理PowerToys Awake 防休眠指南3 种模式让电脑不再意外入睡PowerToys Awake 防休眠指南3 种模式让电脑不再意外入睡 下载卡在 99%、编译只剩最后几步电脑却自己睡着了进度停在原地。Windows 自大数据数据分析批处理流处理机器学习图计算LanceDB Node.js Index 类完全指南向量索引与标量索引的创建、参数调优与实战LanceDB Node.js Index 类完全指南向量索引与标量索引的创建、参数调优与实战 本文以 LanceDB JavaScript SDK la数据库向量数据库全文检索人工智能上一篇COM3D2.MaidFiddler完全指南如何成为女仆管理大师下一篇Reloaded-II终极指南如何快速搭建跨平台游戏修改框架创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考