ActionDB 扩展 OB GIS 能力:新增 ST_PointN 函数

如何扩展 OceanBase 的 GIS 功能?看 ActionDB 技术团队的一个小案例。

作者:爱可生 ActionDB 技术团队。

爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。

本文约 1900 字,预计阅读需要 6 分钟。

在江苏省某行政单位的 ActionDB 项目中,由于强依赖于地图,功能涉及大量坐标处理,而 OceanBase 原生几何属性函数(Geometry Property Functions)无法满足需求,需要在地理信息系统(Geographic Information System,简称 GIS)功能中增加 ST_PointN 函数

面对这一挑战,ActionDB 技术团队深入解析了 OceanBase 中已有的 GIS 函数,包括从表达式解析到算法调用的完整逻辑链路。为了实现 ST_PointN 函数,技术团队需在现有基础上注册 ST_PointN 相关元信息,并开发地理(GEO)函数的对应实现,确保 ST_PointN 函数的无缝集成与高效运行。

ST_PointN 函数介绍

ST_PointN 函数用于在给定的几何对象中提取第 N 个点,常用于几何对象分析和地理信息系统(GIS)中。ST_PointN 函数接受一个几何对象(如线或多边形)和一个索引 N,返回该几何对象的第 N 个点。该函数的主要作用是帮助用户从复杂的几何对象中提取具体的点,以便进行进一步的地理分析或处理。

有哪些常见的应用场景?

  • 道路和路线分析:在分析交通路线时,可以提取路线中的特定点以进行详细分析或优化。
  • 环境监测:用于从多边形或线型区域中提取监测点,从而对环境数据进行更精确的分析。
  • 城市规划:在城市规划中,能够从复杂的多边形中提取特定点以帮助规划人员做出决策。
  • 导航系统:导航系统中,通过提取路径中的关键点,优化导航指引和路径规划。

函数功能实现

如何添加注册信息?

添加 ST_PointN 函数 注册信息,需要在 OceanBase 已有的 GIS 相应信息后追加内容。

  1. 定义函数名:在头文件中 ob_name_def.h 中添加函数名名称,以便在其他地方使用和引用。

  2. 定义函数 ID:为函数分配一个唯一的 ID,每个 GIS 系统函数(T_FUN_SYS_ST_xx)的 ID 不重复。

  3. 添加序列化信息:所有的函数与表达式需要在 ObExpr::EvalFunc g_expr_eval_functions 注册,用于函数信息的序列化。

  4. 注册函数实现类:在工厂方法 register_expr_operators 中注册函数实现类,使其可在执行 SQL 查询时被识别并使用。

  5. 添加函数与 GIS 算法的对应信息:由 ob_geo_func_register 维护函数与 GIS 算法的对应关系,添加相应信息。

如何实现 ST_PointN 函数?

算法功能的实现包含两部分:

  1. ObExprSTPointN

表达式处理的入口,负责 GIS 算法参数的有效性检查,并准备 GIS 上下文。

在 SQL 表达式的执行阶段,位于 src/sql/engine/expr 目录下的各模块负责处理各种不同类型的 SQL 表达式(包括 GIS 函数)。该类主要在算法执行前检查输入参数的有效性,并准备好执行 GIS 算法所需的上下文环境。

  1. ObExprSTPointN 算法实现

一旦 ObExprSTPointN 类完成参数检查后,它会调用 ObGeoFunc::geo_func::eval 方法。这会触发模板分发逻辑,最终执行具体的算法模块 ObGeoFuncPointNImpl,实现 ST_PointN 的功能。

1. 添加函数实现类

添加接口说明:

  • calc_result_type1:检查传递参数类型和数量是否正确。

    • calc_result_type 族函数以后缀识别不同的参数个数,如 calc_result_type1 为一个函数参数。
  • eval_st_PointN:检查所生成的 GIS 对象是否合法,检查 GIS 元数据与 GIS 上下文。

    1. 调用 ObGeoTypeUtil 工具类的各个检查接口。
    2. 设置 GIS 函数执行所需的 GIS 对象与 GIS 上下文(gis_ctx),并检查 GIS 相关对象有效。
    3. 验证完成后,最后会调用 ObGeoFunc<ObGeoFuncType::PointN>::geo_func::eval(gis_context, result) 进入模板函数的分发逻辑,最终选择 ObGeoFuncPointNImpl 模块中匹配的 eval 函数。
2. 添加算法实现

实现 ponitN 的 GIS 处理的核心逻辑。

第一步,注册支持的入参 GIS 子类型(如 linestringmulti_point)。

第二步,定义 eval 族函数。

第三步,自定义的 pointN 函数。

Boost.Geometry 没有直接提供 pointN 函数,但可以通过访问几何体的内部结构实现类似功能。此方法适用于大多数 Boost.Geometry 提供的几何类型(如 linestringmulti_point)。

方案优势

量身定制,满足特定需求
  • 定制化: 通过添加自定义 GIS 函数,如 ST_PointN,可以根据具体应用需求量身定制数据库功能,确保数据库能够精准地满足业务需求,提高数据处理的灵活性和效率。
提高性能和效率
  • 优化算法: 自定义 GIS 函数可以根据实际应用场景进行性能优化,比通用的开源解决方案更高效。这样可以减少复杂 GIS 操作的计算时间,提高查询性能。
增强系统可扩展性
  • 功能扩展: 自定义函数为系统增加了新的功能模块,使得 OceanBase 更加多样化和强大,能够支持更广泛的数据操作需求和业务场景。
提升用户体验
  • 功能丰富: 用户可以直接在数据库中定制函数, 替代复杂的业务 GIS 操作,而不需要借助外部工具或额外的开发工作,简化了开发流程,提高了用户体验和开发效率。
数据安全性和一致性
  • 内部实现: 自定义 GIS 函数在数据库内部实现,减少了数据传输过程中的安全隐患,保证了数据处理的一致性和安全性。
适应快速变化的业务需求
  • 灵活性: 自定义函数使得数据库可以快速响应和适应不断变化的业务需求,无需等待开源社区的更新或第三方工具的升级,显著提高了开发和部署速度。

总结

通过上述步骤,在 OceanBase 中添加并实现了 ST_PointN 函数。具体包括定义函数名和 ID、注册函数、参数类型检查、执行上下文设置、模板函数分发和具体算法实现等子步骤。

最终,通过调用自定义的 pointN 函数,实现了在 OceanBase 中 GIS 功能的扩展。

ST_PointN 函数 的实现,进一步步丰富了 ActionDB 的 GIS 功能矩阵,提升了其在地理信息处理领域的应用价值与竞争力。ActionDB 本着依托开源回馈开源的初衷,本文讨论的 GIS 功能已经提交给 OceanBase 社区版,相信下一个版本可以使用。

什么是 ActionDB?

ActionDB 作为一款卓越的企业级分布式数据库,其设计核心依托于 OceanBase 的开源内核,辅以爱可生在开源数据库领域的深厚积累与技术专长,荣获原厂的正式授权及内核级技术支持。

ActionDB 集 OceanBase 的稳健性与高性能于一身,更进一步强化了与 MySQL 的兼容性,融合爱可生独有的安全特性与用户友好的运维管理工具,缔造了更高品质、更全面的数据库解决方案。

ActionDB 的 MySQL 8.0 协议全面兼容能力,辅以基于 MySQL binlog 的双向复制技术,为业务系统与下游数据平台提供了安全无虞、无缝迁移的完美方案,确保数据迁移的零风险与无感知。

更多技术文章,请访问:https://opensource.actionsky.com/

关于 SQLE

SQLE 是一款全方位的 SQL 质量管理平台,覆盖开发至生产环境的 SQL 审核和管理。支持主流的开源、商业、国产数据库,为开发和运维提供流程自动化能力,提升上线效率,提高数据质量。

✨ Github:https://github.com/actiontech/sqle

📚 文档:https://actiontech.github.io/sqle-docs/

💻 官网:https://opensource.actionsky.com/sqle/

👥 微信群:请添加小助手加入 ActionOpenSource

🔗 商业支持:https://www.actionsky.com/sqle

<think>好的,我现在需要解决的问题是如何通过一个std::unique_ptr<ob::Device>类型的指针来创建std::shared_ptr<ob::Pipeline>对象。用户提到了“管道流对象”,可能是指某种资源管理或数据流处理的类。首先,我得回忆一下C++中智能指针的转换机制,尤其是如何从unique_ptr转换到shared_ptr。 首先,std::unique_ptr是独占所有权的智能指针,不能直接复制,但可以转移所有权。而std::shared_ptr允许多个指针共享同一对象的所有权。因此,可能需要将unique_ptr的所有权转移给shared_ptr。根据C++标准,可以通过释放unique_ptr的资源并手动管理,或者更安全地使用std::move来转移所有权。 用户提到创建std::shared_ptr<ob::Pipeline>,但原始指针是unique_ptr<ob::Device>,这里可能需要确认ob::Pipeline和ob::Device之间的关系。假设Pipeline的构造函数需要Device对象,或者Device对象需要被Pipeline管理。因此,可能需要将Device的所有权转移给Pipeline的shared_ptr。 可能的步骤是:首先,从unique_ptr中释放出原始指针,然后用这个指针构造shared_ptr。但这样会有风险,因为如果unique_ptr已经释放了资源,再使用原始指针会导致问题。更安全的方式是使用std::move将unique_ptr转换为shared_ptr,前提是Device对象可以被多个shared_ptr实例共享。 查阅C++文档,发现可以直接通过移动unique_ptr来构造shared_ptr。例如: std::unique_ptr<ob::Device> dev = ...; std::shared_ptr<ob::Pipeline> pipe(new ob::Pipeline(std::move(dev))); 但这里需要确认Pipeline的构造函数是否接受unique_ptr<Device>参数。如果构造函数需要的是Device*,则可能需要释放unique_ptr的所有权,并将原始指针传递给shared_ptr。例如: std::unique_ptr<ob::Device> dev = ...; ob::Device* raw_dev = dev.release(); std::shared_ptr<ob::Pipeline> pipe(new ob::Pipeline(raw_dev)); 但这样需要确保Pipeline在内部正确管理raw_dev的生命周期,否则可能导致内存泄漏。或者,如果Pipeline的构造函数接受shared_ptr<Device>,则需要将unique_ptr转换为shared_ptr<Device>,然后再传递给Pipeline的构造函数。例如: std::unique_ptr<ob::Device> dev = ...; std::shared_ptr<ob::Device> shared_dev = std::move(dev); std::shared_ptr<ob::Pipeline> pipe = std::make_shared<ob::Pipeline>(shared_dev); 这种情况下,shared_dev现在拥有Device对象的所有权,而pipe则持有shared_dev的引用。需要注意的是,一旦unique_ptr被移动,原来的dev变为nullptr,不能再被使用。 另外,必须确保ob::Pipeline的构造函数确实接受std::shared_ptr<ob::Device>作为参数,否则可能需要调整参数类型或使用其他方法。如果构造函数只需要Device*,并且不接管所有权,那么需要在创建shared_ptr时指定删除器,但这可能比较复杂。 总结可能的步骤:首先将unique_ptr转移到shared_ptr<Device>,然后将该shared_ptr传递给Pipeline的构造函数。或者,如果Pipeline可以直接接受unique_ptr,则移动它。需要查看ob::Pipeline的构造函数的具体要求。 注意事项包括:确保转移所有权后不再使用原来的unique_ptr,避免双重释放或内存泄漏;确认Pipeline对象是否需要共享Device实例的所有权;以及正确管理生命周期,防止悬空指针。</think>要将$std::unique\_ptr<ob::Device>$转换为$std::shared\_ptr<ob::Pipeline>$,需根据$ob::Pipeline$的构造函数要求选择以下两种方法: ### 方法一:所有权转移(推荐) 若$ob::Pipeline$构造函数接受$std::shared\_ptr<ob::Device>$参数: ```cpp std::unique_ptr<ob::Device> uniqueDevice = ...; std::shared_ptr<ob::Device> sharedDevice = std::move(uniqueDevice); // 所有权转移 std::shared_ptr<ob::Pipeline> pipeline = std::make_shared<ob::Pipeline>(sharedDevice); ``` - **优势**:生命周期自动管理 - **验证点**:需确认$ob::Pipeline$构造函数是否支持该参数类型[^1] ### 方法二:直接构造 若构造函数需要原始指针: ```cpp std::unique_ptr<ob::Device> uniqueDevice = ...; std::shared_ptr<ob::Pipeline> pipeline( new ob::Pipeline(uniqueDevice.release()), [](ob::Pipeline* p){ delete p->getDevice(); delete p; } // 自定义删除器 ); ``` - **注意事项**: 1. 必须实现自定义删除器释放关联资源 2. 需明确$ob::Pipeline$析构时是否自动销毁关联设备 3. 原始指针构造的$shared\_ptr$无法直接转为$weak\_ptr$ ### 关键验证点 1. 通过SDK文档确认$ob::Pipeline$的构造函数签名 2. 检查设备对象是否需要跨线程共享 3. 测试所有权转移后的$unique\_ptr$是否自动置为$nullptr$
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值