Tile-based feature requests for extent - any way to revert to standard?

1275
6
09-24-2020 01:12 PM
BrianKeller
New Contributor II

Hi, I see that with 100.9 ArcGIS SDK is sending several requests per layer when the extent changes. We routinely test with Fiddler and immediately noticed the increase on upgrade from 100.7 to 100.9. We see this is due to this enhancement:

Feature Layers now use tile-based requests to fetch and display features in a map when the underlying feature service supports this capability. Feature tiles enable ArcGIS Runtime to display more features from the service and provides faster initial load time by generalizing complex geometries for display. Feature tiles use a Protocol Buffers binary format to compress the data being transferred along with advanced HTTP caching semantics to reduce the impact of network latency and improve performance. At this release, feature tiles are not used to request features for display in a scene (3D).

Is there any way to tell the SDK to use standard requests for extent queries (besides disabling the capability on the feature service)?

It would be nice to either globally set a flag on the client to use standard requests and/or set it on a per layer basis. Our users routinely have minimum 50 layers visible. Instead of 50 requests when they move the map, now we might see 300 requests. If any of those layers perform poorly, the effect of poor performance compounds.

Separately, I am seeing the data return in json and not "Protocol Buffers binary format" - not really an issue, just an observation.

Thanks!

0 Kudos
6 Replies
JamesBallard1
Esri Regular Contributor

Hi Brian Keller‌,

   Thanks for reaching out to us about this. There are a few things at play here. If you are seeing JSON responses, then the Runtime is not making the newer requests which would be coming back in PBF format as you indicated.

Can you check the services you are using to see if they support this newer feature? You need to check for these two attributes:

supportsCoordinatesQuantization
supportsQueryWithResultType

For example you can see both of these are set to true with this service.

https://services.arcgis.com/jIL9msH9OI208GCb/ArcGIS/rest/services/ACS_2016_Tracts_Education/FeatureS... 

If this was working properly, there should be no need to fallback to the previous/older way of requesting the data, so having a switch shouldn't be needed. It looks like there is something else at play in this case.

Can you check the FeatureRequestMode that is set?

- Geodatabase Enums | ArcGIS for Developers 

I am surprised to hear that more requests are going out with 100.9 compared to 100.7. I would like to get to the bottom of that. If you set the FeatureRequestMode on the ServiceFeatureTable to FeatureRequestMode::OnInteractionCache, do you see the performance improve (a reduction in network requests) back to 100.7 levels?

ServiceFeatureTable Class | ArcGIS for Developers 

You can also set the feature request mode via the LoadSettings for the map. That will filter down to all feature tables if you are using a web map. That way you don't need to programmatically walk the entire map to get all the tables and set the request mode on each one.

Here's a way to do that:

LoadSettings* loadSettings = new LoadSettings(this);
loadSettings->setFeatureRequestMode(FeatureRequestMode::OnInteractionCache);
Map* map = new Map(QUrl("your webmap url here"), this);
map->setLoadSettings(loadSettings);

Also, I am assuming you're using the C++ SDK. Let me know if you're using QML and I can tweak the recommendations and code snippets accordingly.

0 Kudos
BrianKeller
New Contributor II

Hi James, thanks for the reply. Our feature services report:

"supportsCoordinatesQuantization": true,
"supportsQueryWithResultType": true,

but also (maybe this is related?)

"supportedQueryFormats": "JSON, geoJSON"

We do not set FeatureRequestMode, and I think by default it uses OnInteractionCache, right? We use QML, and I did set featureRequestMode: Enums.FeatureRequestModeOnInteractionCache just to test - I see no change in the number of queries.

I fired up the 100.7 app and 100.9 app to see the parameters being sent. Approximately 6 queries per layer on 100.9 on a swipe of the map to the right, with just 1 query in 100.7. Example parameters below, removed outFields

100.7:

f json
geometry {"xmin":-9754688.5980574563,"ymin":5144905.825081734,"xmax":-9754285.8681001626,"ymax":5145158.4307802767}
geometryType esriGeometryEnvelope
inSR 3857
maxAllowableOffset 0.000000
outSR 4326
returnDistinctValues false
returnGeometry true
returnM false
returnZ true
spatialRel esriSpatialRelEnvelopeIntersects

100.9:

f json
geometry {"xmin":-9754664.2386693377,"ymin":5144976.3738752119,"xmax":-9754587.8016410526,"ymax":5145052.810903497}
geometryPrecision 0
geometryType esriGeometryEnvelope
inSR 3857
outSR 4326
quantizationParameters {"mode":"view", "originPosition":"upperLeft","tolerance":0.000000083913137,"extent":{"type":"extent","xmin":-13829886.018444981426001,"ymin":2665722.322176279034466,"xmax":-7187861.637385762296617,"ymax":8600914.461163187399507}}
resultType tile
returnDistinctValues false
returnExceededLimitFeatures false
returnGeometry true
returnM false
returnZ true
spatialRel esriSpatialRelEnvelopeIntersects

Wouldn't by nature resultType = tile send more requests? I was reading here about the differences in what that means: Query (Feature Service/Layer)—ArcGIS REST API | ArcGIS for Developers 

Thanks

0 Kudos
JamesBallard1
Esri Regular Contributor

Brian Keller‌,

   >and I think by default it uses OnInteractionCache, right?

Correct.

>We use QML...

Thanks for confirming that.

>I fired up the 100.7 app and 100.9 app to see the parameters being sent. Approximately 6 queries per layer on 100.9 on a swipe of the map to the right, with just 1 query in 100.7

I checked with the team that implemented this feature and here is what I found out. Feature tiling is still supported even when PBF is not, so this is the expected behavior you are seeing. In this case, instead of a single large request for all features, it will request tiled sections with fewer features for each tile. There is some uncertainty about how much overall data is being requested, but it is possible that it will be more now. Previously with a single request, you would be limited by the service's maxRecordCount. Now with the tiled requests, all of those smaller requests may add up to more features overall than the maxRecordCount.

So overall, each of the 6 requests should be requesting less data compared to the single request at 100.7.

Can you check this and see if the data payload for the increased requests at 100.9 is less, the same (roughly) or more than the single request at 100.7?

0 Kudos
BrianKeller
New Contributor II

James Ballard‌,

I'm getting the impression that the extent query by tiles is not configurable and that it's considered better generally. I understand that it has some benefits. By breaking the extent requests into tiles, you can get more features in smaller chunks - potentially exceeding the normal maxRecordCount. This makes a lot of sense for dense features or zoomed out map scales.

I do see some tile queries getting HTTP 304 Not Modified as I pan around, which I don't think I ever saw with the standard implementation - so there is no data transfer and it uses cache. Awesome!

Many of my layers are only visible between max scale 0 and min scale 2000. My features are not that dense at those scales and I rarely worry about maxRecordCount. In my testing, I've been right around 1:500 scale. Most of the extent queries are returning empty results or very small results. The payloads are so variable that it's hard for me to compare unless I setup some automated movements of the map between versions, which I can do.

I'm not concerned about the data size. What concerns me is the overall request count and the total time it takes for those requests to complete. Each layer is generally returning in 80-100ms. When I do one swipe of the map at this scale on 100.7, I measured about 600-800ms for approximately 50 layers to load that new extent. When I did the same in 100.9 showing approximately 6 times the # of requests, it was between 2.6 and 4.7 seconds. I just did a few rounds of this, not super scientific. I'm guessing this is because the requests don't all fire simultaneously. There seems to be some queueing or batching taking place. This can add up fast! Especially if the user is panning around or zooming. And way worse if any layer along the way takes longer to respond, it seems to hold up the requests.

(Side note, I would love to know how HTTP requests are queued or batched with the Qt runtime and if this is configurable.)

One of the issues I see with extent requests overall taking longer because there are more of them, is that it seems an identifyLayersWithMaxResults call waits for them all to finish. If the user finds feature(s) they want to identify after panning, it just seems to hang there while all of these background extent requests finish. Maybe it gets added to the end of the queue or maybe it's purposefully waiting for the extent queries. How can I get the identify to fire/return immediately? I had asked whether the full object query can be skipped before (How to avoid full query with identify ) but the answer was not possible. So would it make sense to prioritize the identify queries over the extent queries? I can open another question for this - it likely deserves a separate thread of conversation. We get user complaints on this frequently, that identify appears to "hang" and not respond after panning the map. This is my main concern in general, even in 100.7, but it is worse with the tile queries.

Would it make sense to set some minimum size for tiles, so that as you zoom in, you're not still splitting an already small extent into multiple tiles?

In my testing the extent queries are taking longer to finish because there are more of them. This directly impacts the user's ability to identify quickly after panning. If we're not able to turn off tile requests or get them to finish in the same amount of time as standard extent queries, I don't think we will be upgrading. I will continue to do testing and comparison, but would love to see this configurable or discuss other options. Thanks!

0 Kudos
JamesBallard1
Esri Regular Contributor

Brian Keller‌,

>I would love to know how HTTP requests are queued or batched with the Qt runtime and if this is configurable...

We use QNetworkAccessManager internally, which is likely why you see requests getting queued up.

QNetworkAccessManager Class | Qt Network 5.15.1 

>Note: QNetworkAccessManager queues the requests it receives. The number of requests executed in parallel is dependent on the protocol. Currently, for the HTTP protocol on desktop platforms, 6 requests are executed in parallel for one host/port combination.

So even if the responses are 304, we still have to wait for that to come back and with ~6X requests I can see what you are describing as being a bottleneck that can actually make overall performance worse.

There are some follow up questions in your last reply that would be better served as new posts so we can look into them.

As for this issue, I will raise what you described internally but I would urge you to follow up with Esri Support so we can be sure to track this. Requests taking longer overall is not the intended outcome.

I did get some ideas for general optimizations you can do from my colleagues. Some of these only work if you're able to configure the services:

>* If they are not editing the layers, they can make them read-only. Then the SDK will not use feature tiling if number of features doesn't exceed maxRecordCount
>* For editable layers, see if they can enable PBF also
>* Can use MANUAL_CACHE mode and populate the features only when required. (we now also have LoadSettings::setFeatureRequestMode)

>...Only thing to note is that maxRecordCount could be tileMaxRecordCount of the service.

0 Kudos
JamesBallard1
Esri Regular Contributor

Hi @BrianKeller,

I want to let you know that the 100.10 release is now available, and we've added the ability to opt-out of feature tiling at the map level now. I think this would help alleviate the problem you're seeing.

https://developers.arcgis.com/qt/qml/api-reference/qml-esri-arcgisruntime-loadsettings.html 

On the LoadSettings object, which you can set on a web map prior to loading it, you can set the featureTilingMode now. If you specify Enums.FeatureTilingModeDisabled, then feature tiling will be disabled entirely in your map for all feature layers.

0 Kudos