华为OD机试 - 服务失效判断(Java 2025 B卷 200分)

本文详细解析了华为OD机试2023B卷中关于服务失效判断的问题,涵盖输入输出描述、解题思路、Java算法源码及效果展示。通过对依赖关系和故障服务的分析,找出并输出所有正常工作的服务。

一、题目描述

某系统中有众多服务,每个服务用字符串(只包含字母和数字,长度<=10)唯一标识,服务间可能有依赖关系,如A依赖B,则当B故障时导致A也故障。依赖具有传递性,如A依赖B,B依赖C,当C故障时导致B故障,也导致A故障。给出所有依赖关系,以及当前已知故障服务,要求输出所有正常服务。

依赖关系:服务1-服务2表示“服务1”依赖“服务2”

不必考虑输入异常,用例保证:依赖关系列表、故障列表非空,且依赖关系数,故障服务数都不会超过3000服务标识格式正常。

二、输入描述

半角逗号分隔的依赖关系列表(换行)。

半角逗号分隔的故障服务列表。

三、输出描述

依赖关系列表中提及的所有服务中可以正常工作的服务列表,用半角逗号分隔,按依赖

关系列表中出现的次序排序。

特别的,没有正常节点输出单独一个半角逗号。

例如:

1、输入

a1-a2,a5-a6,a2-a3
a5,a2

2、输出

a6,a3

3、说明

  • 所有服务+最先出现的序号:{a1=0, a2=1, a3=5, a5=2, a6=3}
  • 故障的服务:[a1, a2, a5]
  • 正常的服务+最先出现的序号:{a3=5, a6=3}
  • 输出a6,a3
  • <
<think> 我们面对的问题是:在Python代码中多次调用OpenRouteService API获取OD(起点-终点)轨迹最优路径时,进行几次调用后就提示调用失败。这通常是由于API调用频率超过限制(如每钟/每小时调用次数限制)或并发请求过多导致的。 ### 解决方案 #### 1. **理解API调用限制** - 查阅OpenRouteService API文档,明确其调用限制(如免费/付费计划的每钟最大请求数、每小时最大请求数等)。例如,免费计划可能限制为每钟40次请求,每小时2000次请求[^3]。 - 错误提示可能为`429 Too Many Requests`,表示超出速率限制。 #### 2. **添加延时控制** 在每次API调用之间添加适当延时(如使用`time.sleep()`),确保不超过API的速率限制: ```python import time def call_api_with_delay(origin, destination, delay_seconds=1.5): # 调用API获取路径 result = get_route(origin, destination) # 假设get_route是封装的API调用函数 time.sleep(delay_seconds) # 延时,控制调用频率 return result ``` - **关键参数**:`delay_seconds`应根据API限制计算。例如,若限制每钟40次,则每次调用至少间隔 `60秒/40次 = 1.5秒`。 #### 3. **批量请求优化** OpenRouteService支持批量请求(如矩阵API),一次性获取多个OD对的最优路径,减少调用次数: ```python # 示例:使用OpenRouteService的Directions API批量请求 import requests def batch_request(od_pairs, api_key): url = "https://api.openrouteservice.org/v2/directions/driving-car" headers = {"Authorization": api_key} # 构建批量请求体(根据API文档格) body = {"locations": [pair for pair in od_pairs], "metrics": ["distance"]} response = requests.post(url, json=body, headers=headers) return response.json() ``` - **优点**:将多个请求合并为1次调用,大幅降低调用频率[^2]。 #### 4. **错误重制** 当API返回错误(如429或5xx错误)时,自动重: ```python import time import requests MAX_RETRIES = 3 def safe_api_call(url, params, headers, retries=MAX_RETRIES): for attempt in range(retries): try: response = requests.get(url, params=params, headers=headers) if response.status_code == 200: return response.json() elif response.status_code == 429: # 超出速率限制 # 根据返回头计算等待时间(如Retry-After),或默认等待 wait_time = int(response.headers.get("Retry-After", 10)) time.sleep(wait_time) else: # 其他错误直接抛出 response.raise_for_status() except requests.exceptions.RequestException as e: if attempt == retries - 1: raise e time.sleep(2 ** attempt) # 指数退避 return None ``` #### 5. **缓存已计算结果** 对相同OD对的请求进行缓存,避免重复调用: ```python from functools import lru_cache @lru_cache(maxsize=1000) def get_cached_route(origin, destination, api_key): return get_route(origin, destination, api_key) # 实际调用API ``` #### 6. **任务调度(大规模调用)** 如需处理超大规模OD对(如数万条),使用任务队列(如Celery)散请求: ```python from celery import Celery app = Celery('tasks', broker='redis://localhost:6379/0') @app.task def async_get_route(origin, destination): return get_route(origin, destination) ``` - 通过Celery的速率限制功能控制并发(如每钟40次)[^1]。 ### 实施步骤 1. **确认API限制**:查阅OpenRouteService文档,明确免费/付费账户的调用限额。 2. **代码改造**: - 在现有调用逻辑中加入延时(步骤2)。 - 实现错误重(步骤4)和缓存(步骤5)。 3. **测验证**:模拟批量请求,检查是否仍出现失败。 4. **监控调整**:记录调用次数和失败率,动态调整延时参数。 ### 相关问题 1. 如何监控OpenRouteService API的调用使用量? 2. 除了延时控制,还有哪些方法可以优化大规模API调用的性能? 3. 在系统中如何同步多个节点的API调用以避免超限? [^1]:【华为OD】查找接口成功率最优时间段(深度优先搜索(DFS)实现Java&Python&C++&JS)。在任务调度中,Celery的速率限制制类似解决API调用频率问题。 [^2]:【华为OD考真题】- 静态代码扫描服务(B-100)(Python版)。批量请求优化类似于静态代码扫描中的合并处理逻辑,减少IO次数。 [^3]:【华为OD考真题】- 查找接口成功率最优时间段(B-100)(Python)。错误重制与成功率统计相关,确保在失败后重以提高整体成功率。 </think>### Python代码多次调用OpenRouteService API失败的解决方案 在使用OpenRouteService API获取OD(起点-终点)轨迹最优路径时,多次调用后出现失败通常由以下原因导致: 1. **API调用频率超限**:OpenRouteService对免费账户有严格调用限制(默认40次/钟) 2. **请求格错误**:坐标格错误或参数缺失 3. **网络连接问题**:不稳定网络导致连接中断 4. **认证问题**:API密钥失效或未正确传递 5. **服务器端限制**:API服务端的保护制触发 #### 解决方案(代码实现示例) ```python import requests import time import json from functools import lru_cache # 1. 添加延时控制(解决频率限制问题) def get_route_with_retry(api_key, start, end, max_retries=3, delay=1.5): """ 带重制的路径请求函数 :param api_key: 您的API密钥 :param start: 起点坐标 [经度, 纬度] :param end: 终点坐标 [经度, 纬度] :param max_retries: 最大重次数(默认3次) :param delay: 请求间隔(秒),免费账户建议≥1.5秒 """ url = "https://api.openrouteservice.org/v2/directions/driving-car" headers = { 'Authorization': api_key, 'Content-Type': 'application/json; charset=utf-8' } body = { "coordinates": [start, end], "instructions": "false", "preference": "recommended" } for attempt in range(max_retries): try: response = requests.post(url, json=body, headers=headers) response.raise_for_status() # 检查HTTP错误 # 2. 检查API返回的错误信息 if response.json().get('error'): error_msg = response.json()['error'].get('message', 'Unknown API error') raise Exception(f"API Error: {error_msg}") return response.json() except requests.exceptions.RequestException as e: print(f"Attempt {attempt+1} failed: {str(e)}") if attempt < max_retries - 1: # 3. 指数退避策略 - 失败后等待时间递增 sleep_time = delay * (2 ** attempt) print(f"Retrying in {sleep_time:.1f} seconds...") time.sleep(sleep_time) else: raise except json.JSONDecodeError: print("Invalid JSON response") raise return None # 4. 添加结果缓存(避免重复请求相同路径) @lru_cache(maxsize=100) def get_cached_route(api_key, start_tuple, end_tuple): """缓存最近100次请求结果,start_tuple和end_tuple为(经度,纬度)元组""" return get_route_with_retry(api_key, list(start_tuple), list(end_tuple)) # 使用示例 if __name__ == "__main__": API_KEY = "your_api_key_here" # 替换为实际API密钥 # 坐标示例(格:[经度, 纬度]) OD_pairs = [ ([8.681495, 49.41461], [8.687872, 49.420318]), ([8.681495, 49.41461], [8.687872, 49.420318]), # 重复请求将被缓存 ([9.70093, 52.37403], [9.73525, 52.34028]) ] for start, end in OD_pairs: try: # 5. 添加延时控制(确保每钟请求<40次) time.sleep(1.5) # 免费账户最小间隔 # 使用缓存函数 result = get_cached_route(API_KEY, tuple(start), tuple(end)) print(f"Route from {start} to {end}: {result['routes'][0]['summary']['distance']} meters") except Exception as e: print(f"Failed to get route: {str(e)}") # 6. 重要失败处理(如写入日志或报警) ``` #### 关键优化点说明 1. **频率控制制**(核心) - 使用 `time.sleep(1.5)` 确保请求间隔 ≥ 1.5秒(免费账户要求) - 指数退避策略:失败后等待时间按 `delay * (2 ** attempt)` 递增 2. **智能缓存系统** - 通过 `@lru_cache` 缓存最近100次请求结果 - 相同OD对直接返回缓存结果,减少API调用 3. **健壮的错误处理** - 自动重制(默认3次) - 详细错误日志记录 - API返回错误消息解析 4. **请求格标准化** - 强制坐标格为 `[经度, 纬度]` - 自动添加必需的请求头: ```python headers = { 'Authorization': api_key, 'Content-Type': 'application/json; charset=utf-8' } ``` #### 进阶优化建议 1. **升级到付费计划**: - 专业版提供更高调用限额(1000次/钟) - 访问:https://openrouteservice.org/plans/ 2. **使用异步请求**(大规模批量处理时): ```python import asyncio import aiohttp async def fetch_route(session, url, headers, data): async with session.post(url, json=data, headers=headers) as response: return await response.json() # 创建异步任务列表 tasks = [fetch_route(session, url, headers, body) for body in bodies] results = await asyncio.gather(*tasks) ``` 3. **监控API使用量**: ```python # 在响应头中获取使用量信息 remaining = int(response.headers.get('X-RateLimit-Remaining', 0)) reset_time = int(response.headers.get('X-RateLimit-Reset', 60)) if remaining < 5: # 剩余次数不足时自动延长间隔 time.sleep(reset_time + 2) ``` ### 相关问题 1. 如何获取OpenRouteService API密钥?不同套餐的调用限制有什么区别? 2. 使用异步请求处理大规模OD对时需要注意哪些并发控制问题? 3. 除了驾车路线,OpenRouteService还支持哪些交通方的路径规划? 4. 当API返回`429 Too Many Requests`错误时,如何自动调整请求策略? > 建议在使用前详细阅读官方文档:https://openrouteservice.org/documentation/ > 特别注意坐标格要求:GeoJSON格 `[经度, 纬度]`(与常规纬度在前相反)[^2]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哪 吒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值