-
-
Notifications
You must be signed in to change notification settings - Fork 362
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
Suggest street names in quest #235
Comments
This is more complex to implement than you might think because the app would need to persistently store all the street names and clean them up as well when they are not needed anymore. |
On the other hand it's really important that StreetComplete doesn't generate wrong entries in the map. I even think the user's first choice should be picking a name from the list and typing the name manually should be an option. It doesn't have to store all the street names persistently. If it is the app that generates tasks on the fly, then one additional query for a street names in a small bounding box should not make a big difference. If the quests are generated by some server, then a street name task should have a list of nearby streets associated and the data would be removed when the task is solved. This way only the names needed for creating the lists are stored and they are automatically removed when not needed. |
Imagine you are in, say, Kenia and you are the first person to ever walk this street since the street was added via satellite imagery. You wouldn't want a list of nearby streets to select, you will want to add the street name. Anyway, this issue is a valid request. The implementation should look like that you have a free input text, but a small down-arrow on the right from which you can select streets which share a node with this street. |
Yes, I understand your intention. What I say is: most common use of this quest will not comply with your intention and it will create many more errors on these links, than add really new street names in Kenya. How about trying to create a list from a small bounding box and adjacent (i.e. sharing node with way in question) ways and if the list is empty - present a box for entering a name. But if the list is not empty - present a list of names as the first option. This way you have both targets covered - it's easy to enter a new name where the vicinity is void of street names, and at the same time we are protected against entering similar, but not exact same names for the same street. EDIT: if the bounding box is a little bit greater than a box just containing the way in question, adding adjacent ways will be redundant. So, getting the street names from a small bounding box ("a bit bigger than only big enough to contain the way") will be enough. EDIT: Actually, if the user is presented with a list of names but still chooses to add new name, I would even suggest setting additional tag to allow finding such entries and prevent vandalism. The tag could be: streetcomplete:newname=New name created, please check. When the name is correct, remove this tag. |
We have enough FIXME like special tags which no one is checking. For example USA was filled with tiger:checked=no tags. This just does not worked. |
A suggestion: JOSM avoids this problem by using auto complete based on the letters entered already. Then the interface would look the same, but if there is King Street and King Lane nearby, you could either pick one of them or insist to create King Square |
That's true. But consider:
Actually, the amount of objects with streetcomplete:newname tag can be even much more smaller, because SC could also remove this tag. This is how:
It is important, that list of names should be taken from and used for every object that contains street name i.e. name=* on highways and addr:street=* on buildings. And every such object should be marked with streetcomplete:newname tag if the user gets the list of nearby street names, but chooses to add a new name.
That's a good idea, provided that autocomplete suggests every name that contains the typed string, not only the names that begin with it. Otherwise the users will tend to create "Patton Street" even when they should choose "General Patton Street" from the list. |
Actually from my own experience I'd say most quests of this type are only small links between some streets missing a name – so the contrary of what you intended. Of course, I'm not in Kenia, but both input methods should be possible. |
Thought a bit about how to implement it properly. This is quite complex if it should be proper. Requirements:
Solution would involve:
Given the complexity of this, this is not exactly a low hanging fruit. So I will not work on this anytime soon |
By the way, @rmikke, there is no server. StreetComplete (the app) generates all quests from analyzing OSM data queried through Overpass. |
Disclaimer: While I am a programmer and know quite a lot about databases and user interaction, I have never programmed even the simplest web or mobile app, so please be patient if I write something stupid ;) I think you overcomplicate a little bit. Getting dataFirst of all, limiting list of names to the names of neighbouring ways seems too strict:
For example, street named Somestreet1 has three nodes, so we get to local database three entries for it in form (more or less):
and then, some unnamed street has any node within 30 meters of any of those nodes, the name Somestreet1 appears on the list of proposed names. On choosing or entering a name we add way's nodes to the above list. This way there would be no graph building, no Overpass querying for every single way. Multilingual namesHow is this problem solved now? Without list of suggestions the street may also have two names in two languages - how does the user enter these two names? If it's not solved yet then I agree that this should be dealt with prior to working on suggestion lists. UIHere I insist that the user should be presented with a list of suggestions (if there exist any) first and have to deliberately choose some "Enter new street name" option to enter a new name. Otherwise quite a big part of users will start typing before they even think there may be some list and all the idea of avoiding entering multiple versions of the same street name is lost and we may not bother as well. Also, I think the same suggestions list should be used when the user enters addr:street for a building. |
Yes, could be. Your suggestion looks quite simple, I like that. I assume you mean there should be two tables, one
The overpass querying (once), by the way, needs to be done either way. But it can be done in the same query that is used to create the quests, so it is no problem.
They can enter them soon. The feature has been developed in a branch and is about to be merged to master. |
I suggest to prepare list of nodes when overpass returns data in table with:
There are two questions here. When retrieving data from overpass there is no problem really, Now, when SC builds suggestions list, I think it will be enough to loop through the way's nodes and for each node find all nodes from the table
Don't :) |
Okay, I am not sure if you can make reasonable suggestions from your point of view because you don't know how the the quest creation and persistence process works. I'll try sum it up: First, you need to know that the download process is decoupled from displaying and solving the quests. The app is not a web app, it downloads the quests once and then keeps them and all other information that is necessary to solve the quests stored in a local DB persistently. Importantly, the app does not make any http queries after the quests were downloaded and before the changes are uploaded. The process is as follows. Download:
Display & Solving quests:
Uploading quests is done by a separate process:
|
Users can download quests at different locations. You can scan for quests in Krakow, then scan for quests in Prague. Your suggestion would mean that the Krakow name suggestion data is cleared on that second scan. |
Thanks, it's more clear for me now. And it seems that in such an arrangement clearing data is not a hard task. But before I make more suggestions, one question is important:
Does that mean, that data stored in DB for a quest is associated somehow with each quest (specific building or bus stop for example) by some Well, that were two questions ;) |
See the links in the last comment for how the tables look. |
How I decide. I.e. like this: https://github.com/westnordost/StreetComplete/blob/master/app/src/main/java/de/westnordost/streetcomplete/data/osm/persist/ElementGeometryDao.java#L146 Same for OSM element table |
Okay then, this structure tells me that so far there was no need to store any data about objects other then quest subjects. Now let me get my wife from the airport and think how to evolve this without revolution, I will come up with something. |
Correct. |
Ooookay. First, from now on everywhere I talk about name, it is a name to suggest, taken either from highway's name or building's addr:street. So I think we need two new tables: First:
This is a simplified version of your NodeTable. We don't need version as we won't update these nodes, we don't need all the tags, and we don't want to use the NodeTable because it contains nodes that are parts of quest subjects and we want to store quite a different set of nodes. Second:
This is to maintain many-to-many relation between quests and names. There will be a third table to temporarily store ways, description below. How to fill tablesFilling NamesAroundTableFirst we fill NamesAroundTable from query similar to this one (I've added relations for complex buildings, still some tweaking required, like adding more highway types, also it should be modified if we want to use it also to suggest street names for addr:street). We want to "propagate" street names from relations and ways to nodes and put those nodes with names into NamesAroundTable. This will require temporary table
to store all ways until we have NamesAroundTable filled. Now, we go through query results, it contains nodes first, then ways, then relations.
Then we go through WaysAroundTable and for each way we lookup it's nodes in NamesAroundTable and update NAME. Then we purge the WaysAroundTable, it's no longer needed. Why we don't care about overwriting namesFirst, because they will usually will be overwritten with the same value. Second, because even if not, we will have the overwritten value in another way/node, that does not belong to relation/way with the new value for name, so we will get the name anyway. Filling QuestToNamesTableFor every unnamed way (a quest) we loop through it's nodes (I can see they are stored in a blob in WayTable) and for every node we loop through nodes in NamesAroundTable and compare latitudes and longitudes of the nodes (node in quest and node from NamesAroundTable). If latitudes difference is less than half a radius (i.e.15m, half of 30m) and longitude difference is less then half a radius, we insert QUEST_ID, NAMED_NODE_ID into QuestToNamesTable. This will cover slightly bigger area, than covered by overpass query, but I can't see a problem here. And just comparing latitudes and longitudes will be faster than trying to select named nodes in circular area around quest's nodes. NOTE: If we use the same algorithm to suggest street names for building's addresses, we have to take into consideration, that quest may be a single node, or a relation, not a way. Creating the list of suggestionWe simply
When the user selects or types a street name for the questWe add the quest's nodes to NamesAroundTable in a loop. For every node we look up all the quests that may require suggestion and if any node of such a quest is within range from a node, we add QUEST_ID, NAMED_NODE_ID to QuestToNameTable. If for this node we don"t add anything to QuestToNameTable, we delete the node from NamesAroundTable. I is also possible to hold the node and check quests' nodes for proximity and only if we find one, we add the node to NamesAroundTable and then add an entry to QuestToNamesTable (in that sequence, because of foreign key constraint on NAMED_NODE_ID in QuestToNamesTable). Cleaning unnecessary dataIt has to be done in this sequence: From QuestToNamesTableWe delete all rows having QUEST_ID that can't be found in OsmQuestTable, analogically to your current cleanup procedure. From NamesAroundTableWe delete all rows having NAMED_NODE_ID that can't be found in QuestToNamesTable. |
Hm your suggestion doesn't sound exactly easier than my original proposal, just different. The problem with discussion the implementation in such a detail is that at some point it does not help the implementer anymore since he will be expected to read through all this here (again) when he finally implements it. That "he" will most likely be me anyway, so I will have to write a short summary later on anyway as I did already a few days ago. Anyway, a few comments regarding your deliberations:
Based on your ideas/suggestions, I will write a final note for implementer(s) later today that contains the requirements and how it should be implemented. I will accept a PR that follows this recipe. This is also meant as an invitation for you to contribute, since you already looked into the subject. I will not leave you (or anyone else who will have a go at this) hanging if he is stuck. Also, if there is a PR, I can shift my priorities and implement the UI side completely within that PR. |
If you can reverse the order (nodes, ways, relations) of data returned by overpass, then you don't need temporary table, because you will have names before nodes. Or you don't mind going through this data mutiple times, then the order of data doesn't matter.
You are right. This also means that you need to generate this blob from tags in such a way, that when you compare two name blobs created for the same set of name:xx=* tags, the blobs will be the same. Hmm, is it possible at all to compare blobs?
Well, it MAY happen that such a street will also not have any buildings with addr:street with it's name and we would lose the name completely. So... To avoid this we have to change:
and then we can store the same node multiple times for multiple names. This will also complicate filling the table a little bit, because we have to:
That's because I imagine that doing it at display time will be to slow for the user. I may be wrong. But UI-wise, the user should not wait for generating suggestions list.
But I did. The section When the user selects or types a street name for the quest works well regardless whether the user chooses existing name or types in a new one.
That's of course true, I just thought that doing it at display time may be too slow for the enduser. Again, I may be wrong.
But you remember that I have close to null knowledge of coding a mobile app? Understanding the DB structure from unknown language (especially if the code is quite clear, as in this case, and uses well known SQL to create tables) and coding in this same language are different things :) I think I could add the code to create tables, but filling them from overpass query is beyond me. |
Rather than writing down the stuff here I put that in code as discussed. Of course, it's only the tables for now, nothing else. |
Now it seems that I have overcomplicated this a bit :D The schema you defined should do the trick. One remark: How do you intend to fill in names from relations? Otherwise, the schema seems to be able to cover all the tasks (getting data, linking to quests, adding solved quests to data and cleaning unnecessary data). So far so good. Oh, and I still hope you will get also street names from addr:street in buildings and use the same mechanism to suggest street names for addr:place when asking for building's address. Beacuse it's the same set of names after all. |
I will just disregard relations. street names are usually found on ways only. Can you help me with the SQL expression that selects all road_names.names given a quest_id? I always mix up the different methods of merging / joining tables. |
SELECT names FROM road_names INNER JOIN road_names_quest_suggestions USING way_id WHERE road_names_quest_suggestions.quest_id = X? |
But street names are sometimes found on relations also. Relation:associatedStreet can also take the name of the street. In practice, street name will be on way and relation in most cases of Relation:associatedStreet, so it does not hurt to search only ways and disregard relations, I guess. |
Buildings with
This, or
You might also try |
Now designed in a way that it can be used for other quests as well, i.e. for #213
Hi again. There is a new tool for mismatched names (in Poland and should be treated as alpha version for now), so I've got a showcase now. See how many cases of street names typed differently it shows. It is a real problem. Could we return to the concept of mutual matching street names in name=* and addr:street=* ? By mutual matching I mean taking both fields into consideration when suggesting a value for name=* for highways and addr:street=* for buldings. I can open a new issue, if it's convenient for you. |
Have you analyzed how many wrong names were added using recent StreetComplete versions that include name suggestions? |
Probably not possible:
On the other hand:
If I get the Overpass query that creates suggestion list now, I can modify it to include street names from addr:street as well. |
There really should be suggestions for street names in street name quests.
The list could be taken from adjacent streets (with common nodes) or by searching highway names and add:street nearby.
Without it users will be entering similar, but not identical names for street parts that are missing name=* tag. You may bet on it - we will end up with a few similar street names for the same street if users can't just select the name if it's already entered for other part of the street.
The text was updated successfully, but these errors were encountered: