Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Landmark Routing 1 PR: Add primary key for landmark database and landmark getter via primary key #4224

Merged
merged 12 commits into from
Aug 2, 2023

Conversation

vesperlou
Copy link
Contributor

@vesperlou vesperlou commented Jul 27, 2023

Issue

To faciliate landmark storage in tiles, primary key is added in landmark databse to enable getting a landmark via its primary key.

Tasklist

  • add primary key to the landmarks database
  • add a method to be able to retreive a landmark from the db via its primary key

Requirements / Relations

Landmark Routing 3: Tile Storage of Associated Landmarks

ret = sqlite3_prepare_v2(db, select, strlen(select), &bounding_box_stmt, NULL);
if (ret != SQLITE_OK) {
throw std::runtime_error("Sqlite prepared select statement error: " +
std::string(sqlite3_errmsg(db)));
}

// prep the landmark getter statement
const char* get_landmark = "SELECT id, name, type, X(geom), Y(geom) FROM landmarks WHERE id = ?";
Copy link
Member

@nilsnolde nilsnolde Jul 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for clarity I'd rename get_landmark to get_landmark_by_id and everything bbox related to get_landmarks_by_bbox (note the plural).

Copy link
Member

@kevinkreiser kevinkreiser Jul 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you meant the function name below in this case not the prepared statement right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

both but primarily the (public) function name, right. the prepare statement and variable names could/should be changed similarly, but that's more of a nit

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we decided we wanted batching we'd either have to not use a prepared statement OR use one with a set level of batching. the latter would be like:

Suggested change
const char* get_landmark = "SELECT id, name, type, X(geom), Y(geom) FROM landmarks WHERE id = ?";
const char* get_landmark = "SELECT id, name, type, X(geom), Y(geom) FROM landmarks WHERE id IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";

or maybe even programatically adding more question marks, and then when we fill them out in the query below we'd need to just repeat the last one until we've filled up all the question marks. if the batch size the person gave us in the vector was too small. and do more than 1 batch if the batch size the person gave us in the vector was too large

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added get_landmarks_by_ids to flexibly fetch multiple landmarks by ids. the statement is not prepared in advance anymore and no min/max limit of landmark number is set. maybe we should set a max number?

Comment on lines 211 to 214
int landmark_type = -1;
if (sqlite3_column_type(get_landmark_stmt, 2) != SQLITE_NULL) {
landmark_type = sqlite3_column_int(get_landmark_stmt, 2);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can't happen can it? if so, we should throw I think. passing on a value of -1 would do crazy things.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i agree, i think we can just skip the if completely and set the type without checking null. we dont ever put a null entry in the db so we cant ever get a null entry out

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it

Comment on lines 252 to 253
if (sqlite3_column_type(bounding_box_stmt, 2) != SQLITE_NULL) {
landmark_type = sqlite3_column_int(bounding_box_stmt, 2);
Copy link
Member

@nilsnolde nilsnolde Jul 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment holds here, type can't be optional

Copy link
Member

@nilsnolde nilsnolde left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some nits:)

@@ -202,17 +245,18 @@ std::vector<Landmark> LandmarkDatabase::get_landmarks_in_bounding_box(const doub

int ret = sqlite3_step(bounding_box_stmt);
while (ret == SQLITE_ROW) {
const char* name = reinterpret_cast<const char*>(sqlite3_column_text(bounding_box_stmt, 0));
uint32_t landmark_id = static_cast<uint32_t>(sqlite3_column_int(bounding_box_stmt, 0));
Copy link
Member

@kevinkreiser kevinkreiser Jul 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
uint32_t landmark_id = static_cast<uint32_t>(sqlite3_column_int(bounding_box_stmt, 0));
auto landmark_id = static_cast<int64_t>(sqlite3_column_int64(bounding_box_stmt, 0));

@@ -60,7 +60,7 @@ enum class LandmarkType : uint8_t {
casino = 18,
};

using Landmark = std::tuple<std::string, LandmarkType, double, double>;
using Landmark = std::tuple<uint32_t, std::string, LandmarkType, double, double>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
using Landmark = std::tuple<uint32_t, std::string, LandmarkType, double, double>;
using Landmark = std::tuple<int64_t, std::string, LandmarkType, double, double>;

std::vector<Landmark> get_landmarks_in_bounding_box(const double minLat,
const double minLong,
const double maxLat,
const double maxLong);

Landmark get_landmark(const uint32_t pkey);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Landmark get_landmark(const uint32_t pkey);
Landmark get_landmark(const int64_t pkey);

@@ -183,6 +194,38 @@ void LandmarkDatabase::insert_landmark(const std::string& name,
pimpl->vacuum_analyze = true;
}

Landmark LandmarkDatabase::get_landmark(const uint32_t pkey) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i wonder if we should allow batching, this could improve efficiency when we are fetching these things:

Suggested change
Landmark LandmarkDatabase::get_landmark(const uint32_t pkey) {
std::vector<Landmark> LandmarkDatabase::get_landmark(const std::vector<int64_t>& pkeys) {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good idea. maybe we should allow both cases

@vesperlou vesperlou requested a review from nilsnolde July 31, 2023 07:07
if (i > 0) {
sql += ", ";
}
sql += "?";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can put the actual value here instead of ? and omit preparing the statement

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done. but i notice sqlite officially suggests to use preparing statement when query includes variables.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likely because they’re doing some internal validation of the variable type or so. I think in our use case here it’s fine to do as it is now, it’s not a multi-variable statement, just the same many times.

const double maxLong) {
// get multiple landmarks by their ids
std::vector<Landmark> LandmarkDatabase::get_landmarks_by_ids(const std::vector<int64_t>& pkeys) {
sqlite3_stmt* get_landmarks_by_ids_stmt = nullptr;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should put a TODO to test how this performs and see if we should prepare a default query (like 10-20 elements) and if more come in we extend the statement preparation

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

@@ -60,7 +60,7 @@ enum class LandmarkType : uint8_t {
casino = 18,
};

using Landmark = std::tuple<std::string, LandmarkType, double, double>;
using Landmark = std::tuple<int64_t, std::string, LandmarkType, double, double>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm I just realized this: not that we really need it but why not uint64_t for the index?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because the primary key has to be a signed 64 bit integer to get a free index on that column in sqlite. why they picked signed i do not know but if we want to use unsigned that means we have to add our own index. anyway this is what i read on the internet. if we were going to do something like that we should forget the primary key and use the osmid directly and add an index manually (this could be useful for debugging at some point?) but i figured at the moment its not needed, it did cross my mind though!

Comment on lines 99 to 101
* database connection is read-only or read-write.
* @param db_name The file path of the SQLite database to connect to.
* @param read_only Set to true to open the database in read-only mode, false for read-write.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

very nitpicky but we typically do this extra white space:

Suggested change
* database connection is read-only or read-write.
* @param db_name The file path of the SQLite database to connect to.
* @param read_only Set to true to open the database in read-only mode, false for read-write.
* database connection is read-only or read-write.
*
* @param db_name The file path of the SQLite database to connect to.
* @param read_only Set to true to open the database in read-only mode, false for read-write.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

kevinkreiser
kevinkreiser previously approved these changes Aug 2, 2023
@kevinkreiser
Copy link
Member

@nilsnolde are you good with the changes? anything else needed here?

nilsnolde
nilsnolde previously approved these changes Aug 2, 2023
@vesperlou vesperlou dismissed stale reviews from nilsnolde and kevinkreiser via 69f88fa August 2, 2023 06:48
@vesperlou
Copy link
Contributor Author

oops @nilsnolde @kevinkreiser I add a new commit to add extra space in docstrings after your approvals. can either of you review again? :)

Copy link
Member

@nilsnolde nilsnolde left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚢

@nilsnolde nilsnolde merged commit 8b0155b into master Aug 2, 2023
8 checks passed
@nilsnolde nilsnolde deleted the jz_landmark_database_add_primary_key branch August 2, 2023 08:13
eikes pushed a commit to eikes/valhalla that referenced this pull request Aug 28, 2023
@vesperlou vesperlou changed the title Add primary key for landmark database and landmark getter via primary key Landmark Routing 1 PR: Add primary key for landmark database and landmark getter via primary key Sep 21, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants