Make forward/reverse weight/offset calculated at query time,

rather than being cached in the StaticRTree.  This means we
can freely apply traffic data and not have stale values lying
around.  It reduces the size of the RTree on disk, at the expense
of some additional data in RAM.
This commit is contained in:
Daniel Patterson
2016-01-29 17:52:20 -08:00
parent 03d360b7bf
commit 49441fe204
24 changed files with 760 additions and 175 deletions
+176 -3
View File
@@ -2,6 +2,9 @@
#include "contractor/graph_contractor.hpp"
#include "extractor/edge_based_edge.hpp"
#include "extractor/compressed_edge_container.hpp"
#include "util/static_rtree.hpp"
#include "util/deallocating_vector.hpp"
@@ -31,6 +34,7 @@
#include <string>
#include <thread>
#include <vector>
#include <iterator>
namespace std
{
@@ -74,8 +78,10 @@ int Contractor::Run()
util::DeallocatingVector<extractor::EdgeBasedEdge> edge_based_edge_list;
std::size_t max_edge_id = LoadEdgeExpandedGraph(
config.edge_based_graph_path, edge_based_edge_list, config.edge_segment_lookup_path,
config.edge_penalty_path, config.segment_speed_lookup_path);
config.edge_based_graph_path, edge_based_edge_list,
config.edge_segment_lookup_path, config.edge_penalty_path,
config.segment_speed_lookup_path, config.node_based_graph_path,
config.geometry_path, config.rtree_leaf_path);
// Contracting the edge-expanded graph
@@ -130,7 +136,10 @@ std::size_t Contractor::LoadEdgeExpandedGraph(
util::DeallocatingVector<extractor::EdgeBasedEdge> &edge_based_edge_list,
const std::string &edge_segment_lookup_filename,
const std::string &edge_penalty_filename,
const std::string &segment_speed_filename)
const std::string &segment_speed_filename,
const std::string &nodes_filename,
const std::string &geometry_filename,
const std::string &rtree_leaf_filename)
{
util::SimpleLogger().Write() << "Opening " << edge_based_graph_filename;
boost::filesystem::ifstream input_stream(edge_based_graph_filename, std::ios::binary);
@@ -184,6 +193,170 @@ std::size_t Contractor::LoadEdgeExpandedGraph(
segment_speed_lookup[std::make_pair(OSMNodeID(from_node_id), OSMNodeID(to_node_id))] =
speed;
}
std::vector<extractor::QueryNode> internal_to_external_node_map;
// Here, we have to update the compressed geometry weights
// First, we need the external-to-internal node lookup table
{
boost::filesystem::ifstream nodes_input_stream(nodes_filename, std::ios::binary);
if (!nodes_input_stream)
{
throw util::exception("Failed to open "+nodes_filename);
}
unsigned number_of_nodes = 0;
nodes_input_stream.read((char *)&number_of_nodes, sizeof(unsigned));
internal_to_external_node_map.resize(number_of_nodes);
// Load all the query nodes into a vector
nodes_input_stream.read(reinterpret_cast<char *>(&(internal_to_external_node_map[0])), number_of_nodes * sizeof(extractor::QueryNode));
nodes_input_stream.close();
}
std::vector<unsigned> m_geometry_indices;
std::vector<extractor::CompressedEdgeContainer::CompressedEdge> m_geometry_list;
{
std::ifstream geometry_stream(geometry_filename, std::ios::binary);
if (!geometry_stream)
{
throw util::exception("Failed to open "+geometry_filename);
}
unsigned number_of_indices = 0;
unsigned number_of_compressed_geometries = 0;
geometry_stream.read((char *)&number_of_indices, sizeof(unsigned));
m_geometry_indices.resize(number_of_indices);
if (number_of_indices > 0)
{
geometry_stream.read((char *)&(m_geometry_indices[0]),
number_of_indices * sizeof(unsigned));
}
geometry_stream.read((char *)&number_of_compressed_geometries, sizeof(unsigned));
BOOST_ASSERT(m_geometry_indices.back() == number_of_compressed_geometries);
m_geometry_list.resize(number_of_compressed_geometries);
if (number_of_compressed_geometries > 0)
{
geometry_stream.read((char *)&(m_geometry_list[0]),
number_of_compressed_geometries * sizeof(extractor::CompressedEdgeContainer::CompressedEdge));
}
geometry_stream.close();
}
// Now, we iterate over all the segments stored in the StaticRTree, updating
// the packed geometry weights in the `.geometries` file (note: we do not
// update the RTree itself, we just use the leaf nodes to iterate over all segments)
{
using LeafNode = util::StaticRTree<extractor::EdgeBasedNode>::LeafNode;
// Open file for reading *and* writing
std::ifstream leaf_node_file(rtree_leaf_filename, std::ios::binary | std::ios::in);
if (!leaf_node_file)
{
throw util::exception("Failed to open "+rtree_leaf_filename);
}
uint64_t m_element_count;
leaf_node_file.read((char *)&m_element_count, sizeof(uint64_t));
LeafNode current_node;
while (m_element_count > 0)
{
leaf_node_file.read(reinterpret_cast<char *>(&current_node), sizeof(current_node));
for (size_t i=0; i< current_node.object_count; i++)
{
auto & leaf_object = current_node.objects[i];
extractor::QueryNode *u;
extractor::QueryNode *v;
if (leaf_object.forward_packed_geometry_id != SPECIAL_EDGEID)
{
const unsigned forward_begin = m_geometry_indices.at(leaf_object.forward_packed_geometry_id);
if (leaf_object.fwd_segment_position == 0)
{
u = &(internal_to_external_node_map[leaf_object.u]);
v = &(internal_to_external_node_map[m_geometry_list[forward_begin].node_id]);
}
else
{
u = &(internal_to_external_node_map[m_geometry_list[forward_begin + leaf_object.fwd_segment_position - 1].node_id]);
v = &(internal_to_external_node_map[m_geometry_list[forward_begin + leaf_object.fwd_segment_position].node_id]);
}
const double segment_length =
util::coordinate_calculation::greatCircleDistance(
u->lat, u->lon, v->lat, v->lon);
auto forward_speed_iter = segment_speed_lookup.find(std::make_pair(u->node_id, v->node_id));
if (forward_speed_iter != segment_speed_lookup.end())
{
int new_segment_weight =
std::max(1, static_cast<int>(std::floor(
(segment_length * 10.) / (forward_speed_iter->second / 3.6) + .5)));
m_geometry_list[forward_begin + leaf_object.fwd_segment_position].weight = new_segment_weight;
}
}
if (leaf_object.reverse_packed_geometry_id != SPECIAL_EDGEID)
{
const unsigned reverse_begin = m_geometry_indices.at(leaf_object.reverse_packed_geometry_id);
const unsigned reverse_end = m_geometry_indices.at(leaf_object.reverse_packed_geometry_id + 1);
int rev_segment_position = (reverse_end - reverse_begin) - leaf_object.fwd_segment_position - 1;
if (rev_segment_position == 0)
{
u = &(internal_to_external_node_map[leaf_object.v]);
v = &(internal_to_external_node_map[m_geometry_list[reverse_begin].node_id]);
}
else
{
u = &(internal_to_external_node_map[m_geometry_list[reverse_begin + rev_segment_position - 1].node_id]);
v = &(internal_to_external_node_map[m_geometry_list[reverse_begin + rev_segment_position].node_id]);
}
const double segment_length =
util::coordinate_calculation::greatCircleDistance(
u->lat, u->lon, v->lat, v->lon);
auto reverse_speed_iter = segment_speed_lookup.find(std::make_pair(u->node_id, v->node_id));
if (reverse_speed_iter != segment_speed_lookup.end())
{
int new_segment_weight =
std::max(1, static_cast<int>(std::floor(
(segment_length * 10.) / (reverse_speed_iter->second / 3.6) + .5)));
m_geometry_list[reverse_begin + rev_segment_position].weight = new_segment_weight;
}
}
}
m_element_count -= current_node.object_count;
}
leaf_node_file.close();
}
// Now save out the updated compressed geometries
{
std::ofstream geometry_stream(geometry_filename, std::ios::binary);
if (!geometry_stream)
{
throw util::exception("Failed to open "+geometry_filename+" for writing");
}
const unsigned number_of_indices = m_geometry_indices.size();
const unsigned number_of_compressed_geometries = m_geometry_list.size();
geometry_stream.write(reinterpret_cast<const char *>(&number_of_indices), sizeof(unsigned));
geometry_stream.write(reinterpret_cast<char *>(&(m_geometry_indices[0])), number_of_indices * sizeof(unsigned));
geometry_stream.write(reinterpret_cast<const char *>(&number_of_compressed_geometries), sizeof(unsigned));
geometry_stream.write(reinterpret_cast<char *>(&(m_geometry_list[0])), number_of_compressed_geometries * sizeof(extractor::CompressedEdgeContainer::CompressedEdge));
geometry_stream.close();
}
}
// TODO: can we read this in bulk? util::DeallocatingVector isn't necessarily