
GraphHopper Java API 路由实战指南Speed / Hybrid / Flexible 三种模式、Heading 方向偏好与备选路线【免费下载链接】graphhopperOpen source routing engine for OpenStreetMap. Use it as Java library or standalone web server.项目地址: https://gitcode.com/GitHub_Trending/gr/graphhopper本篇技术指南以 GraphHopper 官方文档 Routing via Java API 为核心讲解如何将 GraphHopper 路由引擎嵌入你自己的 Java或任意 JVM 语言应用从 Maven 依赖、GraphHopper 实例初始化与GHRequest发起路由到速度模式CH、混合模式LM、灵活模式Dijkstra/A*三种算法的选择与切换再到 Heading 起终点方向约束、备选路线Alternative Routes以及基于 client-hc 的 HTTP 客户端调用。读完本文你将掌握在纯 Java 代码中完成一次完整、可定制、可上线部署的路线规划所需的全部核心能力并了解底层算法与参数的实际来源。前置条件Maven 依赖与示例工程要以 Java 库的形式使用 GraphHopper 路由能力首先需要在构建配置中声明graphhopper-core依赖README.md#mavendependency groupIdcom.graphhopper/groupId artifactIdgraphhopper-core/artifactId version[LATEST-VERSION]/version /dependency其中[LATEST-VERSION]需要替换为你在仓库 CHANGELOG.md 中看到的当前版本号。除了核心模块官方示例工程位于 example/src/main/java/com/graphhopper/example/RoutingExample.java它一次性覆盖了本文接下来要讲的全部场景基础路由、三种模式对比、备选路线、以及基于自定义模型custom model的可定制路由。对应的测试 example/src/test/java/com/graphhopper/example/RoutingExampleTest.java 会以RoutingExample.main(new String[]{../})的方式运行整个示例验证示例中的各项断言如il.size() 6、距离取整后为 600 米等是观察跑通即正确的最直接入口。示例主方法接受一个可选参数作为 OSM 数据文件所在目录默认使用core/files/andorra.osm.pbf这类 OpenStreetMap 数据文件仓库 core/files 目录中还提供andorra.osm.gz、monaco.osm.gz、krautsand.osm.gz等可直接用于测试的小型地图public static void main(String[] args) { String relDir args.length 1 ? args[0] : ; GraphHopper hopper createGraphHopperInstance(relDir core/files/andorra.osm.pbf); routing(hopper); speedModeVersusFlexibleMode(hopper); alternativeRoute(hopper); customizableRouting(relDir core/files/andorra.osm.pbf); // release resources to properly shutdown or start a new instance hopper.close(); }注意最后调用的hopper.close()GraphHopper实例持有图存储、CH/LM 预计算数据等资源显式关闭才能正确释放或在需要时重新启动新实例。Speed 模式 vs. Hybrid 模式 vs. Flexible 模式文档中 GraphHopper 将路由算法划分为三种模式详见 docs/core/routing.md 与 README.md 技术概览模式底层算法是否需要预计算速度灵活性Speed 模式Contraction HierarchiesCH收缩层次结构需要导入阶段做 CH 准备最快最低仅支持预定义 profileHybrid 模式LandmarksLM地标 A*需要LM 准备较快介于二者之间较高支持请求时修改部分属性Flexible 模式Dijkstra 或 A*及其双向变体不需要较慢长路线尤其明显完全灵活三种模式的取舍非常清晰Speed 模式查询最快、单请求内存占用最低且不使用启发式但只能使用预先定义好的 profileHybrid 模式需要额外的时间和内存做 LM 准备但可以在请求层面调整权重例如集成实时交通数据速度比 Flexible 模式快一个数量级Flexible 模式无需任何索引数据换取的是完全的灵活性和较慢的查询。如果对应的准备数据都存在你甚至可以在每次请求时动态切换模式。配置与请求时切换模式对应的 profile 在config.yml仓库中为 config-example.yml里通过profiles_ch与profiles_lm两个配置段声明这与 profile 定义相互独立# Speed mode: profiles you want to use with speed mode need to go here profiles_ch: - profile: car - profile: some_other_profile # Hybrid mode: profiles you want to use with hybrid mode need to go here profiles_lm: - profile: car - profile: some_other_profileconfig-example.yml中默认只对car开启 CH注释说明 foot/bike 默认不做 CH 准备以节省资源profiles_lm默认为空。profile 的完整定义方式profiles段、custom_model、turn_costs等请参见 docs/core/profiles.md。在请求时可以通过 hint 覆盖默认模式选择ch.disabletrue关闭速度模式。此时若所选 profile 存在 LM 准备数据则使用 Hybrid 模式否则退回 Flexible 模式lm.disabletrue在存在 LM 准备数据的情况下强制使用 Flexible 模式。这两个参数名的常量定义可以在 web-api/src/main/java/com/graphhopper/util/Parameters.java 中找到Parameters.CH.DISABLE与Parameters.Landmark.DISABLE其余常用算法常量同样集中定义在此类中例如dijkstra、dijkstrabi、astar、astarbi、alternative_route、round_trip等。示例中speedModeVersusFlexibleMode展示了这一用法——即使 profile 配了 CH 准备请求时显式选择双向 A* 并禁用 CH 也能得到与速度模式相同的路径public static void speedModeVersusFlexibleMode(GraphHopper hopper) { GHRequest req new GHRequest(42.508552, 1.532936, 42.507508, 1.528773). setProfile(car).setAlgorithm(Parameters.Algorithms.ASTAR_BI).putHint(Parameters.CH.DISABLE, true); GHResponse res hopper.route(req); if (res.hasErrors()) throw new RuntimeException(res.getErrors().toString()); assert Helper.round(res.getBest().getDistance(), -2) 600; }实例初始化profile、编码值与 CH 准备createGraphHopperInstance展示了以编程方式构建一个带 CH 速度模式的GraphHopper实例的完整流程static GraphHopper createGraphHopperInstance(String ghLoc) { GraphHopper hopper new GraphHopper(); hopper.setOSMFile(ghLoc); // specify where to store graphhopper files hopper.setGraphHopperLocation(target/routing-graph-cache); // add all encoded values that are used in the custom model, these are also available as path details or for client-side custom models hopper.setEncodedValuesString(car_access, car_average_speed, road_access, road_environment, max_speed, ferry_speed); // see docs/core/profiles.md to learn more about profiles hopper.setProfiles(new Profile(car).setCustomModel(GHUtility.loadCustomModelFromJar(car.json))); // this enables speed mode for the profile we called car hopper.getCHPreparationHandler().setCHProfiles(new CHProfile(car)); // now this can take minutes if it imports or a few seconds for loading of course this is dependent on the area you import hopper.importOrLoad(); return hopper; }几个关键点setOSMFile指定输入地图setGraphHopperLocation指定图数据的落盘缓存目录importOrLoad()首次运行会导入 OSM 并构建 CH之后再次运行则直接从缓存加载耗时取决于地图范围setEncodedValuesString声明参与自定义模型的编码值encoded values这些值同时可作为 path details 或客户端自定义模型使用所有内置编码值在 core/src/main/java/com/graphhopper/routing/ev/DefaultEncodedValueFactory.java 中定义但只有声明进graph.encoded_values的才会进入图存储对应 docs/core/profiles.md 中Setting up Encoded Values一节setProfiles注册名为car的 profile这里直接加载 jar 内置的car.json自定义模型与 YAML 配置中custom_model_files: [car.json]等价getCHPreparationHandler().setCHProfiles(...)对该 profile 启用 CH 准备即开启 Speed 模式。对应的 YAML 等价配置可参考 config-example.yml 中的profiles与profiles_ch段。发起第一次路由请求GHRequest 与 GHResponse路由请求的核心对象是GHRequest定义在 web-api/src/main/java/com/graphhopper/GHRequest.java其字段包括points途经点列表、profileprofile 名称、headings、pointHints、curbsides、pathDetails、algo、locale、customModel以及一个通用的hintsPMap承载ch.disable等所有 hint 参数。GHRequest提供了GHRequest(fromLat, fromLon, toLat, toLon)、new GHPoint(...)加addPoint(...)等多种构造方式天然支持带 via 点的多段路由。一个最小完整示例public static void routing(GraphHopper hopper) { // simple configuration of the request object GHRequest req new GHRequest(42.508552, 1.532936, 42.507508, 1.528773). // note that we have to specify which profile we are using even when there is only one like here setProfile(car). // define the language for the turn instructions setLocale(Locale.US); GHResponse rsp hopper.route(req); // handle errors if (rsp.hasErrors()) throw new RuntimeException(rsp.getErrors().toString()); // use the best path, see the GHResponse class for more possibilities. ResponsePath path rsp.getBest(); // points, distance in meters and time in millis of the full path PointList pointList path.getPoints(); double distance path.getDistance(); long timeInMs path.getTime(); Translation tr hopper.getTranslationMap().getWithFallBack(Locale.UK); InstructionList il path.getInstructions(); // iterate over all turn instructions for (Instruction instruction : il) { // System.out.println(distance instruction.getDistance() for instruction: instruction.getTurnDescription(tr)); } assert il.size() 6; assert Helper.round(path.getDistance(), -2) 600; }要点解读setProfile(car)是必须的——即使实例中只有一个 profile 也要显式指定setLocale(Locale.US)决定转向指示turn instructions的语言可配合hopper.getTranslationMap()按需获取其他语言GraphHopper 支持超过 45 种语言的转向指示rsp.hasErrors()是标准的错误处理入口rsp.getErrors()会返回异常集合如不可达点、参数非法等rsp.getBest()取最优路径返回ResponsePath可继续读取getPoints()几何点列、getDistance()米、getTime()毫秒、getInstructions()转向指示列表等文档中提示本示例与后续章节的完整代码均位于 example/src/main/java/com/graphhopper/example/RoutingExample.java。Heading约束起终点方向文档指出Flexible 与 Hybrid 模式下可以为任意一个点添加期望的 heading以正北为基准的方位角0360 度。添加 heading 后朝向其他方向的道路会被惩罚从而让路线更可能以指定方向出发/到达。Speed 模式CH目前不支持 heading 参数因此使用 heading 时需要通过ch.disabletrue关闭速度模式详见 docs/core/heading.md。关于 heading 的几个硬性规则NaN表示该点不强制方向超出[0, 360]的取值会抛出IllegalArgumentException关键语义在 via 点或终点上强制方向时需要指定的是离开该点的方向outgoing heading。例如想强制从南边进入终点应当填写朝北离开即 0 度。GHRequest.setHeadings(ListDouble)是 Java API 的入口GHRequest.javaheadings 列表长度可以为 0、1仅起点或等于点数。惩罚参数 heading_penalty惩罚力度由heading_penalty参数控制其语义是放弃指定 heading 所接受的额外时间延迟秒。当前源码中默认值为 300 秒定义于 web-api/src/main/java/com/graphhopper/util/Parameters.javaParameters.Routing.DEFAULT_HEADING_PENALTY并在 core/src/main/java/com/graphhopper/routing/DefaultWeightingFactory.java 中作为请求 hint 的兜底默认值使用该值也可在自定义模型中显式设置见 core/src/main/java/com/graphhopper/routing/weighting/custom/CustomModelParser.java。将heading_penalty调低例如 10 秒会使 heading 约束显著放松路线可能回到与不设 heading 时一致的结果。实测效果heading.md中给出了一个完整用例从42.566757, 1.597751到42.567396, 1.597807分别演示了不设 heading、设置起点朝西270°、起点 270° 终点朝南180°即强制从北边来、以及仅设置终点方向起点填NaN四种情况。对比可见设置 heading 后返回了不同的路线上方两图由 heading 文档将结果坐标 LineString 转成 GeoJSON 后绘制用于直观对比方向约束对路径选择的影响。对应的 Java 示例为 example/src/main/java/com/graphhopper/example/HeadingExample.java底层行为的单元测试可参见 core/src/test/java/com/graphhopper/routing/HeadingAndCustomModelRoutingTest.java其中testStartDirection、testStartEndDirection、testViaDirection等用例在小图上验证了起点、终点、via 点方向约束对所选边序列的影响testHeadingWithSnapFilter则验证了 heading 与点吸附snap过滤的交互。备选路线Alternative Routes所有模式都支持计算备选路线但 CH 使用的算法与 LM/Flexible 模式不同CH 场景走AlternativeRouteCHcore/src/main/java/com/graphhopper/routing/ch 模块而非 CH 场景使用AlternativeRoute。无论哪种模式开启备选路线都会对查询性能产生影响。请求时通过setAlgorithm(Parameters.Algorithms.ALT_ROUTE)即alternative_route启用并通过 hints 调整三个核心参数常量见 Parameters.java参数常量作用alternative_route.max_pathsAltRoute.MAX_PATHS最多返回多少条备选路线alternative_route.max_weight_factorAltRoute.MAX_WEIGHT备选路线权重相对最优路线权重的最大倍数大于该倍数的备选会被过滤alternative_route.max_share_factorAltRoute.MAX_SHARE备选路线与最优路线共享路段的最大比例权重单位用于剔除过于相似的路线示例中的用法public static void alternativeRoute(GraphHopper hopper) { // calculate alternative routes between two points (supported with and without CH) GHRequest req new GHRequest().setProfile(car). addPoint(new GHPoint(42.506701, 1.521668)).addPoint(new GHPoint(42.509533, 1.540185)). setAlgorithm(Parameters.Algorithms.ALT_ROUTE); req.getHints().putObject(Parameters.Algorithms.AltRoute.MAX_PATHS, 3); GHResponse res hopper.route(req); if (res.hasErrors()) throw new RuntimeException(res.getErrors().toString()); assert res.getAll().size() 2; assert Helper.round(res.getBest().getDistance(), -2) 1800; }注意示例中虽然请求了max_paths 3实际返回 2 条res.getAll().size() 2——因为其余候选未通过 weight/share 过滤条件。res.getAll()返回全部候选路径res.getBest()是最优的那条。从 core/src/main/java/com/graphhopper/routing/AlternativeRoute.java 的源码注释可以确认其实现思路采用论文中描述的plateau 方法并部分采用 penalty 方法寻找备选路径构造基于共同前缀/后缀的思想保证备选路线与最优路线有明显差异该类继承自AStarBidirection本身就是一个双向 A* 算法。源码还特别提示该算法在长路线上可能较慢备选路线最实用的组合是配合 CH见AlternativeRouteCH。maxWeightFactor默认过滤权重超长的备选、maxShareFactor限制与最优路线的重叠度、explorationFactor控制探索范围调高可能得到更多备选但查询更慢等内部参数都在该类的字段注释中有详细说明。测试用例可参考 core/src/test/java/com/graphhopper/routing/AlternativeRouteTest.java其中通过putObject(alternative_route.max_paths, 3)等写法验证了这些 hint 的实际效果。Java 与 Android 客户端client-hc如果你要调用的是 GraphHopper Directions API 或自建 GraphHopper 服务的 HTTP 接口而不是把引擎嵌入进程内可以直接使用官方client-hcJava 与 Android 客户端位于 client-hc用法见 client-hc/README.md。其核心类是 client-hc/src/main/java/com/graphhopper/api/GraphHopperWeb.java基于 OkHttp 实现支持 GZIP 压缩、GET/POST 两种请求方式并内置X-GH-Client-Version版本头。GraphHopperAPI gh new GraphHopperWeb(); gh.load(http://your-graphhopper-service.com); // or for the GraphHopper Directions API https://graphhopper.com/#directions-api // gh.load(https://graphhopper.com/api/1/route); GHResponse rsp gh.route(new GHRequest(...));要点GraphHopperWeb无参构造默认指向https://graphhopper.com/api/1/route即 Directions API 的路由端点GraphHopperWeb.java也可以通过构造参数或load(url)指向自建服务gh.route(...)接受与内嵌 API 相同的GHRequest对象返回相同的GHResponse结构因此切换进程内引擎与远程服务两种模式几乎不改变业务代码与 Directions API 或自建服务通信时请求/响应模型由 web-api 模块的 Jackson 序列化层定义GraphHopperModule.java 等client-hc 复用了同一套模型相关测试见 client-hc/src/test/java/com/graphhopper/api/GraphHopperWebTest.java 与 client-hc/src/test/java/com/graphhopper/api/Examples.java。除 Java 外GraphHopper 生态还提供 JavaScript 等多种语言的服务端客户端但那是独立仓库不在本仓库范围内。进一步阅读docs/core/profiles.mdprofile 定义、custom_model/custom_model_files、turn_costs以及profiles_ch/profiles_lm配置详解docs/core/heading.mdHeading 参数完整文档与 HTTP 请求示例docs/core/ch.md 与 docs/core/landmarks.mdSpeed 模式Contraction Hierarchies与 Hybrid 模式Landmarks的原理细节docs/core/custom-models.md自定义模型规范支持请求级别的自定义路由docs/core/low-level-api.md更底层的 Java 使用方式docs/web/api-doc.mdHTTP Web API 参数说明profile、point、heading、ch.disable等均可在 URL 中直接使用docs/index.mdGraphHopper 全部文档索引。【免费下载链接】graphhopperOpen source routing engine for OpenStreetMap. Use it as Java library or standalone web server.项目地址: https://gitcode.com/GitHub_Trending/gr/graphhopper创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考