提供 API 键以避免 Apps 脚本中 Maps Service 的 Hit Limit 错误

Supply API key to avoid Hit Limit error from Maps Service in Apps Script

我有一个 Google Sheet,我们通过 Maps Service 获取两个 Lat/Lng 之间的行驶距离。下面的函数有效,但矩阵是 4,500 个单元格,所以我收到 "Hit Limit" 错误。

如何在此处提供我的付费帐户的 API 密钥?

自定义函数

function drivingMeters(origin, destination) {
  if (origin=='' || destination==''){return ''}
  var directions = Maps.newDirectionFinder()
  .setOrigin(origin)
  .setDestination(destination)
  .getDirections();
  return directions.routes[0].legs[0].distance.value ;
}

使用示例:

A1: =drivingMeters($E10,G)

Where E10 = 42.771328,-91.902281
  and G9  = 42.490390,-91.1626620

根据文档,您应该 initialize the Maps service with your authentication details 在调用其他方法之前:

Your client ID and signing key can be obtained from the Google Enterprise Support Portal. Set these values to null to go back to using the default quota allowances.

我建议将这些值存储在 PropertiesService and using CacheService 中以提供快速访问。使用这种方法,而不是将它们写入脚本项目的主体,意味着它们不会被其他编辑者无意中复制、推送到共享代码存储库,或者如果您的脚本作为库发布,则其他开发人员也不会看到它们。

此外,我建议重写您的自定义函数以接受数组输入和 return 适当的数组输出 - 这将有助于加快其执行速度。 Google 在自定义函数页面上提供了一个示例:https://developers.google.com/apps-script/guides/sheets/functions#optimization

使用 props/cache 的示例:

function authenticateMaps_() {
  // Try to get values from cache:
  const cache = CacheService.getScriptCache();
  var props = cache.getAll(['mapsClientId', 'mapsSigningKey']);
  // If it wasn't there, read it from PropertiesService.
  if (!props || !props.mapsClientId || !props.mapsSigningKey) {
    const allProps = PropertiesService.getScriptProperties().getProperties();
    props = {
      'mapsClientId': allProps.mapsClientId,
      'mapsSigningKey': allProps.mapsSigningKey
    };
    // Cache these values for faster access (max 6hrs)
    cache.putAll(props, 21600);
  }
  // Apply these keys to the Maps Service. If they don't exist, this is the
  // same as being a default user (i.e. no paid quota).
  Maps.setAuthentication(props.mapsClientId, props.mapsSigningKey);
}
function deauthMaps_() {
  Maps.setAuthentication(null, null);
}

// Your called custom function. First tries without authentication,
// and then if an error occurs, assumes it was a quota limit error
// and retries. Other errors do exist (like no directions, etc)...
function DRIVINGMETERS(origin, dest) {
  if (!origin || !destination)
    return;
  try {
    return drivingMeters_(origin, dest);
  } catch (e) {
    console.error({
      message: "Error when computing directions: " + e.message,
      error: e
    });
    // One of the possible errors is a quota limit, so authenticate and retry:
    // (Business code should handle other errors instead of simply assuming this :) )
    authenticateMaps_();
    var result = drivingMeters_(origin, dest);
    deauthMaps_();
    return result;
  }
}

// Your implementation function.
function drivingMeters_(origin, dest) {
  var directions = Maps.newDirectionFinder()
  ...
}