Skip to content

Take two at a water layer - #39

Open
ratmice wants to merge 3 commits into
osmus:mainfrom
ratmice:water_layer_pr2
Open

Take two at a water layer#39
ratmice wants to merge 3 commits into
osmus:mainfrom
ratmice:water_layer_pr2

Conversation

@ratmice

@ratmice ratmice commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

I went ahead and added comments to each of the tags I added.
I couldn't really understand how to do navigation without obstructions like dams/weir/waterfalls,
so I did end up including those, let me know if you really want those omitted.

Looking through the keys, they are pretty sparse for most of the regions I tried.
It seemed like one key would appear on a few items in one area. Ditto for a different key on a different region.
(Like open_water in the regions I tried only appeared in finland)

I'm not sure if you'll actually want map_from_tag_list for building a map from related tags.
It seemed weird to have separate columns for each vessel kind, for restricting access by kind of boat,
however the majority of these appear to have cardinality(vessel_access) == 1. So I'm not entirely sure it's the right thing to do.

@jake-low jake-low left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Sorry it took me a couple of weeks to reply to this. I've left a few comments.

I tend to be conservative about which tags to include in each layer, because it's easier to add a column than to remove it. OSM tags wax and wane over time, which works because of its fluid schema. But Layercake attempts to squish OSM into something rigid and typed, so removing a column later (e.g. if the community decides to change how something is tagged) is a breaking change for downstream users who reference that column in their SQL queries or similar. Most of my comments are from that perspective.

Comment thread sql/water.sql Outdated
-- Reason: dimensions.
tags['width'] AS width,
tags['depth'] AS depth,
tags['depth:'] AS 'depth:',

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

depth: looks like a typo?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Or at the very least should be a prefix_map, I'll try and figure out whether I was looking at a depth prefix, before just removing it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I didn't see any of these in the data i've downloaded, but I believe that these were for the prefix_map mentioned in

https://wiki.openstreetmap.org/wiki/Key:depth

They prefix map seems used for things like how the depth tag was obtained/measured it's accuracy, etc.
depth:source_quality, depth:technique, depth:accuracy depth:exposition.

It may just be used more for water bodies than rivers?

Comment thread sql/water.sql Outdated
tags['height'] AS height, -- For waterfalls?

-- Reason: navigation direction and obstruction bypass,
prefix_map('oneway:', tags) AS 'oneway:',

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd avoid using a trailing : in a column name; it's confusing. I also don't think we need to include oneway:* tags at all (yet) since there are only a handful of uses on waterways worldwide currently.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I suppose it doesn't matter if we're just removing the prefix_map, but is there any suggestion/convention for
tags that act as both a prefix_map and a tag? That's why I was using : here in column names.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The convention used in other layers is to pluralize the tag key. E.g. prefix_map('name:', tags) AS names. As a user you can then do SELECT name AS default_name, names['en'] AS english_name or similar which reads pretty well.

This is somewhat awkward for some tag keys though.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Ahh, yeah I think if I recall I might have started doing the : thing after some awkwardness.

tags['rapids'] as rapids,
tags['rapids'] as rapidss,

seems the most likely culprit

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

One thought: prefix_map exists because name:* is an unbounded set of keys (every present and possible future language code, and more), so we can't enumerate it at build time. But rapids:* has a small, known set of keys. The best structure then is probably just to have the following fixed set of columns:

  • rapids
  • rapids:name
  • rapids:class
  • rapids:intermittent
  • (others can be added too but that's probably a good start)

This is how Layercake currently handles similar cases. For example building, building:material, and building:levels are each a top level column in the buildings layer.

An additional advantage of this is that top-level columns can be efficiently filtered or projected in a query; map columns cannot.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I couldn't find anything tagged with rapids:intermittent only two with rapids:class

mostly just rapids:name, plus 62 with rapids:description.

Comment thread sql/water.sql Outdated
-- Reason: navigation direction and obstruction bypass,
prefix_map('oneway:', tags) AS 'oneway:',
tags['oneway'] AS oneway,
tags['canoe_pass'] AS canoe_pass,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

canoe_pass doesn't look like an established tag (only 21 uses)

Comment thread sql/water.sql Outdated
tags['lock'] AS lock,

-- Boat access
map_from_tag_list(tags, ['motorboat', 'ship', 'sailboat', 'boat', 'canoe']) as vessel_access,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think it's clearer to make each of these its own column (this is what the highways layer does).

Comment thread sql/water.sql Outdated
tags['hazard'] AS hazard,

-- Reason: Fish navigation?
tags['fish_pass'] AS fish_pass,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

fish_pass also doesn't look like an established tag (only 76 uses)

Comment thread sql/water.sql Outdated
-- Reason: Fish navigation?
tags['fish_pass'] AS fish_pass,
-- Reason: hydrology
tags['order:strahler'] AS 'order:strahler',

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I don't think this info belongs in OSM; Strahler number can easily be computed and is just one of several methods of analyzing stream topography. So I would not include it in Layercake.

Comment thread sql/water.sql Outdated
prefix_map('oneway:', tags) AS 'oneway:',
tags['oneway'] AS oneway,
tags['canoe_pass'] AS canoe_pass,
tags['lock'] AS lock,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Might also want lock_name and lock_ref if we're including this.

Comment thread sql/water.sql Outdated
-- waterway-relevant tags i've added or changed...
-- Reason: general
tags['usage'] AS usage,
tags['natural'] AS natural,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm unsure whether to include natural; I think most of the values come from a small set (valley, canyon, etc) and it's much more common for those features to be mapped as a separate element, so SELECT * FROM waterways WHERE natural = 'canyon' wouldn't actually be a reliable way to identify waterways that flow through canyons.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think the exact reason I included is was because of https://wiki.openstreetmap.org/wiki/Waterways

If a stream starts as as spring, the node can be tagged with natural=spring.

But now that I look at that it, it's limited to nodes and areas, and this script has a where clause WHERE kind = 'line'

I'll just remove it for now.

Comment thread sql/water.sql Outdated
type,
id,
tags['waterway'] AS waterway,
tags['name'] AS name,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Probably want to split_mutli on name, and include prefix_map_split('names:') too, since major rivers that pass through or form the border between different countries will usually have multiple names.

Comment thread sql/water.sql Outdated
WHERE kind = 'line'
AND tags['waterway'] IN ('river', 'stream', 'canal', 'ditch', 'drain', 'flowline', 'fairway', 'link',
-- Reason: Routing obstructions.
'dam', 'weir', 'waterfall'

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm mixed about whether including dams, weirs, and waterfalls is useful. We do not include barrier elements in the highways layer, which would be necessary for correct highway routing. And it seems like it might surprise data consumers that dams, weirs, and waterfalls are included in the "waterways" layer (IMO this is one of the many confusing things about OSM's taxonomy; natural=waterfall and man_made=dam would be clearer, but alas).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I'll just drop damns, weirs, and waterfalls for now, it can always be added later.

On man_made=dam it isn't really common but there are also natural=beaver_dam it's wiki page is actually hilarious.
https://wiki.openstreetmap.org/wiki/Tag:natural%3Dbeaver_dam

While similar to the man_made=, beaver_made='s use count was too low to be kept as good practice.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Since we removed that I also got rid of height which is probably only useful for waterfalls.

@ratmice

ratmice commented Jul 30, 2026

Copy link
Copy Markdown
Contributor Author

Thank you for the review, I'll try and work on your suggestions tomorrow

@ratmice

ratmice commented Jul 30, 2026

Copy link
Copy Markdown
Contributor Author

I went ahead and pushed some changes, plus some reformatting in a separate commit to make everything look nicer.

One question that I had, is this uses the general Geometry type of duckdb, even though it's doing a WHERE kind = line ,
I think, but am uncertain whether we could use a more specific gemetry type. I think it still needs to be the general Geometry because it could be either LineString or MultiLineString?

Is there a goal of optimizing the geometry for specific types in layercake?

@ratmice

ratmice commented Aug 3, 2026

Copy link
Copy Markdown
Contributor Author

I guess one thing I wonder is if you want to just wait for another person who can use the layer in their program
(since mine needs more than the fields we've discussed), before committing to a set of fields. It probably makes more sense, just to know you're avoiding committing to a set of fields no-one is currently using?

@jake-low

jake-low commented Aug 5, 2026

Copy link
Copy Markdown
Member

One question that I had, is this uses the general Geometry type of duckdb, even though it's doing a WHERE kind = line, I think, but am uncertain whether we could use a more specific geometry type.

DuckDB actually does this automatically when writing parquet files. It observes what types get written into the column and then sets the appropriate type annotation at the end. I checked and the geometry_type annotation in your current version of this layer is [LineString] since that's the only type that appears in it.

I'm not aware of any software that actually uses this info to optimize how it handles the data though, so it's mainly just advisory info that might appear when someone inspects the file.

I guess one thing I wonder is if you want to just wait for another person who can use the layer in their program (since mine needs more than the fields we've discussed), before committing to a set of fields.

I think it's okay to ship this even if we don't know exactly who will use it. There's lots of reasons someone might want to grab all of the waterways in OSM, and this layer makes that easy. The set of attributes we've arrived at feels like a reasonable starting point; we can always tweak it later.

If you mark this PR as "ready for review" I am happy to rebase it, review it, and test it.

@ratmice
ratmice marked this pull request as ready for review August 5, 2026 00:06
@ratmice

ratmice commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

Okay I marked it as ready for review,
I am also happy to take care of the conflicts if that would be helpful.
Thank you for your reviews and attention to detail so far, happy to continue working on it if anything further needs doing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants