Matrix calculation - timed out - Python SDK

Hello all,

I am currently running my ORS on an Azure Virtual Machine running Linux (4 vCPUs, 16GB RAM). Everything seems to be configured correctly and I am using the Python SDK for ORS. However, I am having timed out issues when i try to use the distance matrix api when there are > 1000 coordinates. I have configured everything before on my local machine before (ORS and code), and i still get the same issue even after I host my ORS on Azure VM.
Config and code below.

config.json:

{
  "ors": {
    "info": {
      "base_url": "https://openrouteservice.org/",
      "swagger_documentation_url": "https://api.openrouteservice.org/",
      "support_mail": "support@openrouteservice.org",
      "author_tag": "openrouteservice",
      "content_licence": "LGPL 3.0"
    },
    "api_settings": {
      "cors": {
        "allowed": {
          "origins": [
            "*"
          ],
          "headers": [
            "Content-Type",
            "X-Requested-With",
            "accept",
            "Origin",
            "Access-Control-Request-Method",
            "Access-Control-Request-Headers",
            "Authorization"
          ]
        },
        "exposed": {
          "headers": [
            "Access-Control-Allow-Origin",
            "Access-Control-Allow-Credentials"
          ]
        },
        "preflight_max_age": 600
      }
    },
    "services": {
      "matrix": {
        "enabled": true,
        "maximum_routes": 25000000,
        "maximum_routes_flexible": 20000,
        "maximum_search_radius": 50000000,
        "maximum_visited_nodes": 1000000000,
        "allow_resolve_locations": true,
        "attribution": "openrouteservice.org, OpenStreetMap contributors"
      },
      "isochrones": {
        "enabled": true,
        "maximum_range_distance": [
          {
            "profiles": "any",
            "value": 50000
          },
          {
            "profiles": "driving-car, driving-hgv",
            "value": 100000
          }
        ],
        "maximum_range_time": [
          {
            "profiles": "any",
            "value": 18000
          },
          {
            "profiles": "driving-car, driving-hgv",
            "value": 3600
          }
        ],
        "fastisochrones": {
          "maximum_range_distance": [
            {
              "profiles": "any",
              "value": 50000
            },
            {
              "profiles": "driving-car, driving-hgv",
              "value": 500000
            }
          ],
          "maximum_range_time": [
            {
              "profiles": "any",
              "value": 18000
            },
            {
              "profiles": "driving-car, driving-hgv",
              "value": 10800
            }
          ],
          "profiles": {
            "default_params": {
              "enabled": false,
              "threads": 12,
              "weightings": "recommended",
              "maxcellnodes": 5000
            },
            "hgv": {
              "enabled": true,
              "threads": 12,
              "weightings": "recommended, shortest",
              "maxcellnodes": 5000
            }
          }
        },
        "maximum_intervals": 10,
        "maximum_locations": 2,
        "allow_compute_area": true
      },
      "routing": {
        "enabled": true,
        "mode": "normal",
        "routing_description": "This is a routing file from openrouteservice",
        "routing_name": "openrouteservice routing",
        "sources": [
          "/home/ors/ors-core/data/cambodia-latest.osm.pbf"
        ],
        "init_threads": 1,
        "attribution": "openrouteservice.org, OpenStreetMap contributors",
        "elevation_preprocessed": false,
        "profiles": {
          "active": [
            "car",
            "hgv"
          ],
          "default_params": {
            "encoder_flags_size": 8,
            "graphs_root_path": "/home/ors/ors-core/data/graphs",
            "elevation_provider": "multi",
            "elevation_cache_path": "/home/ors/ors-core/data/elevation_cache",
            "elevation_cache_clear": false,
            "instructions": true,
            "maximum_distance": 100000,
            "maximum_distance_dynamic_weights": 100000,
            "maximum_distance_avoid_areas": 100000,
            "maximum_waypoints": 50,
            "maximum_snapping_radius": 400,
            "maximum_avoid_polygon_area": 200000000,
            "maximum_avoid_polygon_extent": 20000,
            "maximum_distance_alternative_routes": 100000,
            "maximum_alternative_routes": 3,
            "maximum_distance_round_trip_routes": 100000,
            "maximum_speed_lower_bound": 10,
            "preparation": {
              "min_network_size": 200,
              "min_one_way_network_size": 200,
              "methods": {
                "lm": {
                  "enabled": true,
                  "threads": 1,
                  "weightings": "recommended,shortest",
                  "landmarks": 16
                }
              }
            },
            "execution": {
              "methods": {
                "lm": {
                  "disabling_allowed": true,
                  "active_landmarks": 8
                }
              }
            }
          },
          "profile-car": {
            "profiles": "driving-car",
            "parameters": {
              "encoder_flags_size": 8,
              "encoder_options": "turn_costs=true|block_fords=false|use_acceleration=true",
              "maximum_distance": 100000000000,
              "elevation": true,
              "maximum_snapping_radius": 350,
              "preparation": {
                "min_network_size": 200,
                "min_one_way_network_size": 200,
                "methods": {
                  "ch": {
                    "enabled": true,
                    "threads": 1,
                    "weightings": "fastest"
                  },
                  "lm": {
                    "enabled": false,
                    "threads": 1,
                    "weightings": "fastest,shortest",
                    "landmarks": 16
                  },
                  "core": {
                    "enabled": true,
                    "threads": 1,
                    "weightings": "fastest,shortest",
                    "landmarks": 64,
                    "lmsets": "highways;allow_all"
                  }
                }
              },
              "execution": {
                "methods": {
                  "ch": {
                    "disabling_allowed": true
                  },
                  "lm": {
                    "disabling_allowed": true,
                    "active_landmarks": 6
                  },
                  "core": {
                    "disabling_allowed": true,
                    "active_landmarks": 6
                  }
                }
              },
              "ext_storages": {
                "WayCategory": {},
                "HeavyVehicle": {},
                "WaySurfaceType": {},
                "RoadAccessRestrictions": {
                  "use_for_warnings": true
                }
              }
            }
          },
          "profile-hgv": {
            "profiles": "driving-hgv",
            "parameters": {
              "encoder_flags_size": 8,
              "encoder_options": "turn_costs=true|block_fords=false|use_acceleration=true",
              "maximum_distance": 100000000000,
              "elevation": true,
              "preparation": {
                "min_network_size": 200,
                "min_one_way_network_size": 200,
                "methods": {
                  "ch": {
                    "enabled": true,
                    "threads": 1,
                    "weightings": "recommended"
                  },
                  "core": {
                    "enabled": true,
                    "threads": 1,
                    "weightings": "recommended,shortest",
                    "landmarks": 64,
                    "lmsets": "highways;allow_all"
                  }
                }
              },
              "execution": {
                "methods": {
                  "ch": {
                    "disabling_allowed": true
                  },
                  "core": {
                    "disabling_allowed": true,
                    "active_landmarks": 6
                  }
                }
              },
              "ext_storages": {
                "WayCategory": {},
                "HeavyVehicle": {
                  "restrictions": true
                },
                "WaySurfaceType": {}
              }
            }
          },
          "profile-bike-regular": {
            "profiles": "cycling-regular",
            "parameters": {
              "encoder_options": "consider_elevation=true|turn_costs=true|block_fords=false",
              "elevation": true,
              "ext_storages": {
                "WayCategory": {},
                "WaySurfaceType": {},
                "HillIndex": {},
                "TrailDifficulty": {}
              }
            }
          },
          "profile-bike-mountain": {
            "profiles": "cycling-mountain",
            "parameters": {
              "encoder_options": "consider_elevation=true|turn_costs=true|block_fords=false",
              "elevation": true,
              "ext_storages": {
                "WayCategory": {},
                "WaySurfaceType": {},
                "HillIndex": {},
                "TrailDifficulty": {}
              }
            }
          },
          "profile-bike-road": {
            "profiles": "cycling-road",
            "parameters": {
              "encoder_options": "consider_elevation=true|turn_costs=true|block_fords=false",
              "elevation": true,
              "ext_storages": {
                "WayCategory": {},
                "WaySurfaceType": {},
                "HillIndex": {},
                "TrailDifficulty": {}
              }
            }
          },
          "profile-bike-electric": {
            "profiles": "cycling-electric",
            "parameters": {
              "encoder_options": "consider_elevation=true|turn_costs=true|block_fords=false",
              "elevation": true,
              "ext_storages": {
                "WayCategory": {},
                "WaySurfaceType": {},
                "HillIndex": {},
                "TrailDifficulty": {}
              }
            }
          },
          "profile-walking": {
            "profiles": "foot-walking",
            "parameters": {
              "encoder_options": "block_fords=false",
              "elevation": true,
              "ext_storages": {
                "WayCategory": {},
                "WaySurfaceType": {},
                "HillIndex": {},
                "TrailDifficulty": {}
              }
            }
          },
          "profile-hiking": {
            "profiles": "foot-hiking",
            "parameters": {
              "encoder_options": "block_fords=false",
              "elevation": true,
              "ext_storages": {
                "WayCategory": {},
                "WaySurfaceType": {},
                "HillIndex": {},
                "TrailDifficulty": {}
              }
            }
          },
          "profile-wheelchair": {
            "profiles": "wheelchair",
            "parameters": {
              "encoder_options": "block_fords=true",
              "elevation": true,
              "maximum_snapping_radius": 50,
              "ext_storages": {
                "WayCategory": {},
                "WaySurfaceType": {},
                "Wheelchair": {
                  "KerbsOnCrossings": "true"
                },
                "OsmId": {}
              }
            }
          },
          "profile-public-transport": {
            "profiles": "public-transport",
            "parameters": {
              "encoder_options": "block_fords=false",
              "elevation": true,
              "maximum_visited_nodes": 1000000,
              "gtfs_file": "openrouteservice-api-tests/data/vrn_gtfs.zip"
            }
          }
        }
      }
    },
    "logging": {
      "enabled": true,
      "level_file": "DEBUG_LOGGING.json",
      "location": "/home/ors/ors-core/logs/ors",
      "stdout": true
    },
    "system_message": [
      {
        "active": false,
        "text": "This message would be sent with every routing bike fastest request",
        "condition": {
          "request_service": "routing",
          "request_profile": "cycling-regular,cycling-mountain,cycling-road,cycling-electric",
          "request_preference": "fastest"
        }
      },
      {
        "active": false,
        "text": "This message would be sent with every request for geojson response",
        "condition": {
          "api_format": "geojson"
        }
      },
      {
        "active": false,
        "text": "This message would be sent with every request on API v1 from January 2020 until June 2050",
        "condition": {
          "api_version": 1,
          "time_after": "2020-01-01T00:00:00Z",
          "time_before": "2050-06-01T00:00:00Z"
        }
      },
      {
        "active": false,
        "text": "This message would be sent with every request"
      }
    ]
  }
}

Code:

import openrouteservice as ors
client = ors.Client(base_url="http:/xxx/ors")

coordinates_5k = tuple of 5000 coordinates in the correct format

# Distance matrix - 5k customers
matrix = client.distance_matrix(
    locations=coordinates_5k,
    profile="driving-car",
    metrics=["distance", "duration"],
    validate=False,
)

coordinates_5k is already correctly formatted (lon, lat in tuple form) and there are 5000 of them for testing.

Error below:

---------------------------------------------------------------------------
TimeoutError                              Traceback (most recent call last)
File c:\Users\haziq.razak\AppData\Local\anaconda3\lib\site-packages\urllib3\connectionpool.py:449, in HTTPConnectionPool._make_request(self, conn, method, url, timeout, chunked, **httplib_request_kw)
    445         except BaseException as e:
    446             # Remove the TypeError from the exception chain in
    447             # Python 3 (including for exceptions like SystemExit).
    448             # Otherwise it looks like a bug in the code.
--> 449             six.raise_from(e, None)
    450 except (SocketTimeout, BaseSSLError, SocketError) as e:

File <string>:3, in raise_from(value, from_value)

File c:\Users\haziq.razak\AppData\Local\anaconda3\lib\site-packages\urllib3\connectionpool.py:444, in HTTPConnectionPool._make_request(self, conn, method, url, timeout, chunked, **httplib_request_kw)
    443 try:
--> 444     httplib_response = conn.getresponse()
    445 except BaseException as e:
    446     # Remove the TypeError from the exception chain in
    447     # Python 3 (including for exceptions like SystemExit).
    448     # Otherwise it looks like a bug in the code.

File c:\Users\haziq.razak\AppData\Local\anaconda3\lib\http\client.py:1374, in HTTPConnection.getresponse(self)
   1373 try:
-> 1374     response.begin()
   1375 except ConnectionError:

File c:\Users\haziq.razak\AppData\Local\anaconda3\lib\http\client.py:318, in HTTPResponse.begin(self)
    317 while True:
--> 318     version, status, reason = self._read_status()
    319     if status != CONTINUE:

File c:\Users\haziq.razak\AppData\Local\anaconda3\lib\http\client.py:279, in HTTPResponse._read_status(self)
    278 def _read_status(self):
--> 279     line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")
    280     if len(line) > _MAXLINE:

File c:\Users\haziq.razak\AppData\Local\anaconda3\lib\socket.py:705, in SocketIO.readinto(self, b)
    704 try:
--> 705     return self._sock.recv_into(b)
    706 except timeout:

TimeoutError: timed out

During handling of the above exception, another exception occurred:

ReadTimeoutError                          Traceback (most recent call last)
File c:\Users\haziq.razak\AppData\Local\anaconda3\lib\site-packages\requests\adapters.py:489, in HTTPAdapter.send(self, request, stream, timeout, verify, cert, proxies)
    488 if not chunked:
--> 489     resp = conn.urlopen(
    490         method=request.method,
    491         url=url,
    492         body=request.body,
    493         headers=request.headers,
    494         redirect=False,
    495         assert_same_host=False,
    496         preload_content=False,
    497         decode_content=False,
    498         retries=self.max_retries,
    499         timeout=timeout,
    500     )
    502 # Send the request.
    503 else:

File c:\Users\haziq.razak\AppData\Local\anaconda3\lib\site-packages\urllib3\connectionpool.py:787, in HTTPConnectionPool.urlopen(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, **response_kw)
    785     e = ProtocolError("Connection aborted.", e)
--> 787 retries = retries.increment(
    788     method, url, error=e, _pool=self, _stacktrace=sys.exc_info()[2]
    789 )
    790 retries.sleep()

File c:\Users\haziq.razak\AppData\Local\anaconda3\lib\site-packages\urllib3\util\retry.py:550, in Retry.increment(self, method, url, response, error, _pool, _stacktrace)
    549 if read is False or not self._is_method_retryable(method):
--> 550     raise six.reraise(type(error), error, _stacktrace)
    551 elif read is not None:

File c:\Users\haziq.razak\AppData\Local\anaconda3\lib\site-packages\urllib3\packages\six.py:770, in reraise(tp, value, tb)
    769         raise value.with_traceback(tb)
--> 770     raise value
    771 finally:

File c:\Users\haziq.razak\AppData\Local\anaconda3\lib\site-packages\urllib3\connectionpool.py:703, in HTTPConnectionPool.urlopen(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, **response_kw)
    702 # Make the request on the httplib connection object.
--> 703 httplib_response = self._make_request(
    704     conn,
    705     method,
    706     url,
    707     timeout=timeout_obj,
    708     body=body,
    709     headers=headers,
    710     chunked=chunked,
    711 )
    713 # If we're going to release the connection in ``finally:``, then
    714 # the response doesn't need to know about the connection. Otherwise
    715 # it will also try to release it and we'll have a double-release
    716 # mess.

File c:\Users\haziq.razak\AppData\Local\anaconda3\lib\site-packages\urllib3\connectionpool.py:451, in HTTPConnectionPool._make_request(self, conn, method, url, timeout, chunked, **httplib_request_kw)
    450 except (SocketTimeout, BaseSSLError, SocketError) as e:
--> 451     self._raise_timeout(err=e, url=url, timeout_value=read_timeout)
    452     raise

File c:\Users\haziq.razak\AppData\Local\anaconda3\lib\site-packages\urllib3\connectionpool.py:340, in HTTPConnectionPool._raise_timeout(self, err, url, timeout_value)
    339 if isinstance(err, SocketTimeout):
--> 340     raise ReadTimeoutError(
    341         self, url, "Read timed out. (read timeout=%s)" % timeout_value
    342     )
    344 # See the above comment about EAGAIN in Python 3. In Python 2 we have
    345 # to specifically catch it and throw the timeout error

ReadTimeoutError: HTTPConnectionPool(host='20.198.252.227', port=8080): Read timed out. (read timeout=60)

During handling of the above exception, another exception occurred:

ReadTimeout                               Traceback (most recent call last)
File c:\Users\haziq.razak\AppData\Local\anaconda3\lib\site-packages\openrouteservice\client.py:186, in Client.request(self, url, get_params, first_request_time, retry_counter, requests_kwargs, post_json, dry_run)
    185 try:
--> 186     response = requests_method(self._base_url + authed_url,
    187                                **final_requests_kwargs)
    188     self._req = response.request

File c:\Users\haziq.razak\AppData\Local\anaconda3\lib\site-packages\requests\sessions.py:635, in Session.post(self, url, data, json, **kwargs)
    625 r"""Sends a POST request. Returns :class:`Response` object.
    626 
    627 :param url: URL for the new :class:`Request` object.
   (...)
    632 :rtype: requests.Response
    633 """
--> 635 return self.request("POST", url, data=data, json=json, **kwargs)

File c:\Users\haziq.razak\AppData\Local\anaconda3\lib\site-packages\requests\sessions.py:587, in Session.request(self, method, url, params, data, headers, cookies, files, auth, timeout, allow_redirects, proxies, hooks, stream, verify, cert, json)
    586 send_kwargs.update(settings)
--> 587 resp = self.send(prep, **send_kwargs)
    589 return resp

File c:\Users\haziq.razak\AppData\Local\anaconda3\lib\site-packages\requests\sessions.py:701, in Session.send(self, request, **kwargs)
    700 # Send the request
--> 701 r = adapter.send(request, **kwargs)
    703 # Total elapsed time of the request (approximately)

File c:\Users\haziq.razak\AppData\Local\anaconda3\lib\site-packages\requests\adapters.py:578, in HTTPAdapter.send(self, request, stream, timeout, verify, cert, proxies)
    577 elif isinstance(e, ReadTimeoutError):
--> 578     raise ReadTimeout(e, request=request)
    579 elif isinstance(e, _InvalidHeader):

ReadTimeout: HTTPConnectionPool(host='20.198.252.227', port=8080): Read timed out. (read timeout=60)

During handling of the above exception, another exception occurred:

Timeout                                   Traceback (most recent call last)
c:\Users\haziq.razak\OneDrive - DKSH\openrouteservice\test-ors-scripts\ors-KH-test.ipynb Cell 10 line 2
      1 # Distance matrix - 1k customers
----> 2 matrix = client.distance_matrix(
      3     locations=coordinates_5k,
      4     profile="driving-car",
      5     metrics=["distance", "duration"],
      6     validate=False,
      7 )

File c:\Users\haziq.razak\AppData\Local\anaconda3\lib\site-packages\openrouteservice\client.py:299, in _make_api_method.<locals>.wrapper(*args, **kwargs)
    296 @functools.wraps(func)
    297 def wrapper(*args, **kwargs):
    298     args[0]._extra_params = kwargs.pop("extra_params", None)
--> 299     result = func(*args, **kwargs)
    300     try:
    301         del args[0]._extra_params

File c:\Users\haziq.razak\AppData\Local\anaconda3\lib\site-packages\openrouteservice\distance_matrix.py:116, in distance_matrix(client, locations, profile, sources, destinations, metrics, resolve_locations, units, optimized, validate, dry_run)
    113 if optimized is not None:
    114     params["optimized"] = optimized
--> 116 return client.request("/v2/matrix/" + profile + '/json', {}, post_json=params, dry_run=dry_run)

File c:\Users\haziq.razak\AppData\Local\anaconda3\lib\site-packages\openrouteservice\client.py:191, in Client.request(self, url, get_params, first_request_time, retry_counter, requests_kwargs, post_json, dry_run)
    188     self._req = response.request
    190 except requests.exceptions.Timeout:
--> 191     raise exceptions.Timeout()
    193 if response.status_code in _RETRIABLE_STATUSES:
    194     # Retry request.
    195     warnings.warn('Server down.\nRetrying for the {0}{1} time.'.format(retry_counter + 1,
    196                                                                        get_ordinal(retry_counter + 1)),
    197                   UserWarning,
    198                   stacklevel=1)

Timeout: 

I am heavily assuming its due to how my config is setup as I have less experience with it. Can anyone suggest a config for the matrix so I can compute maybe up to 10000 coordinates? Or is it because of machine in Azure VM is not powerful enough to make the matrix computes? Thank you so much for the help!

Hey,

you’re trying to compute 2.5*10^6 values at once.
I’d expect this to take quite some time, so I can easily imagine openrouteservice-py running into a timeout error.

I’d suggest testing your setup with a way smaller dataset (i.e. 50 points) and recording the response times for that. That might give you an idea on how long it will take for your full dataset.

Best regards

Thanks for the quick reply!

Yes, I have used a smaller dataset before and did many tests. It seems that with my config.json above and machine configurations, i can only do up to 1000 points/coordinates and it will sucessfully finish and output it under 35s. However, if i do even 1100 coordinates, it goes over 1min and it times out. Is there a way to make it not time out and let the API run for more than 1000? Is my config.json the problem or is it my machine? Thanks!

Hey,

your config seems fine, but there might still be issues that I don’t see.
It could be that you arrive at a point where the algorithm doesn’t scale linearly anymore, and thus takes quite a bit longer than expected.

If 1000 points are running fine, is it an option to chunk your 5k points into 5 sets and calculate distances pairwise, using the sources and destinations parameters?

Best regards

If 1000 points are running fine, is it an option to chunk your 5k points into 5 sets and calculate distances pairwise, using the sources and destinations parameters?

Sorry where and how do I use the sources and destinations parameters?

Hey,

have a look at our API docs and the openrouteservice-py docs.

Best regards

1 Like

Thank you so much as I just got a workaround to handle my data albeit it takes longer than I though (an hour to compile) but this works for my use case. Code below:

final_duration_df = pd.DataFrame()

for i in range(len(coordinates_5k)):
    matrix = client.distance_matrix(
        locations=coordinates_5k,
        profile="driving-car",
        metrics=["duration"],
        validate=False,
        sources=[i],
    )

    final_duration_df = pd.concat(
        [final_duration_df, pd.DataFrame(matrix["durations"]) / 3600]
    )

This gives me a perfect 5000x5000 duration matrix that i needed. If there are other more efficient workarounds, that will be highly appreciated! Thank you!

Yeah, like this you’re calculating 5000 1-to-5000 matrices.
Even if one calculation takes only a second, you’re already looking at 5000 seconds, i.e. ~1.5 hours.

Something along the lines of

for i in range(len(coordinates_5k)//10): # integer divison for range
    matrix = client.distance_matrix(
        locations=coordinates_5k,
        profile="driving-car",
        metrics=["duration"],
        validate=False,
        sources=[10*i:(10*i)+10], # calculate 10x5000-matrices
    )

    final_duration_df = pd.concat(
        [final_duration_df, pd.DataFrame(matrix["durations"]) / 3600]
    )

might speed up your calculations.
Or think about chunking as mentioned before.

Best regards

1 Like