ThinkGeo.com    |     Documentation    |     Premium Support

Retrieving features from layer using a collection of values

Some of our customers have very large parcel layers (~half a million features). What I’m attempting to do is query this layer however possible with an array of values to return the features associated with those values. In this case, our column is the parcel number. 



I’ve tried a couple approaches. Doing a layer.QueryTools.ExecuteQuery() to retrieve a table of OBJECTID’s where I can then get the features from, and looping through the list of parcel numbers and doing an individual layer…QueryTools.GetFeaturesByColumnValue( ). Both seem to take an extremely long time. 



Code for the former:




parcelLayer.Open(); 


            String query = String.Format(“SELECT OBJECTID FROM {0} WHERE {1} in (’{2}’)”,                      
                    parcelLayer.Name, 
                    ActiveSet.parcelFieldName,
                    String.Join("’, '",parcelList.ToArray()));
 
            DataTable results = parcelLayer.QueryTools.ExecuteQuery( query );            
 
            Collection<string> ids = new Collection<string>(); 


            foreach (DataRow row in results.Rows)
            {
               ids.Add(DataTools.ToType<string>(row[“OBJECTID”]));
            }
 
            Collection<feature> features = parcelLayer.QueryTools.GetFeaturesByIds(ids, ReturningColumnsType.NoColumns); 


            foreach( Feature f in features )
            {
               dynLayer.InternalFeatures.Add( f.Id, f );
            } 


            return;

Any suggestions as to how I can make this faster?





Also from what I’m reading, it looks like we can’t guarantee the feature Id will exist in the shapefile, so therefore this query may not even work. So how am I supposed to retrieve the features associate with this list of parcel numbers? Even if I return all columns, I don’t know of a way to instantiate or access the associated features with the rows from ExecuteQuery()



This is another solution, though even longer than the aforementioned query




Collection<Feature>  features = parcelLayer.FeatureSource.GetAllFeatures(new List<String>() { ActiveSet.parcelFieldName });
 
foreach (Feature f in features)
{
   if( ParcelNumbers.Contains( DataTools.ToType<String>(f.ColumnValues[ActiveSet.parcelFieldName] ) ) )
      dynLayer.InternalFeatures.Add(f.Id, f);
}


Hi Kevin, 
  
 Our ExecuteQuery call the OleDb API. So we should cannot improve the speed of this function. 
  
 I think maybe you can add Stopwatch to make sure which one is slower between the ExecuteQuery and the GetFeaturesByIds, so we can think about how to improve. 
  
 The 2nd way is slower because it read all the features. 
  
 I want to make sure whether you are using ShapeFileFeatureLayer? If so, maybe you can try to move data to memory(InMemoryFeatureLayer), which should be faster. 
  
 Regards, 
  
 Don

Don,



Thank you for your reply. Yes this is pulling from a shapefile. 



I times three different approaches using Thinkgeo interfaces to the data. In these tests I am trying to retrieve 124 parcel features in a shapefile containing 478,055 features. 



Attempt 1: GetAllFeatures() then select features with parcel number in parcel list: 1:10



Attempt 2: ExecuteQuery() with parcel list: ~32 seconds



Attempt 3: Loop through list and call GetFeaturesByColumnValue() for each parcel: ~6 minutes (about 3 seconds per call)





Attempt 2 is obviously the fastest (though I’d still consider it slow), but even so it is not a viable option because we can’t guarantee a column in the shapefile will associate with the actual feature Id, thus we have no way of retrieving the actual features.



I have not tried loading the layer as an inMemoryFeatureLayer. I’m concerned the memory footprint of doing that would be huge.



Currently what I’m going to implement to get around this, if there’s no way I can interact with the data faster, is build a list of key-value pairs that associates a parcel number with a feature Id, and load this on first load of the map. This will allow me to quickly retrieve the associated feature Id’s which should in theory allow me to grab the associated features relatively quickly. I’m open to suggestions of alternatives to this, however.


Hi Kevin, 
  
 It looks we speed most time on ExecuteQuery. And the GetFeaturesByIds step won’t take too much time, right? 
  
 I think your workaround should works, and how to build the index in memory is important. 
  
 Another suggestion is maybe you can did a quickly try on some big database like SQLServer, I am not sure whether the query speed will get improved there, but if it did, it’s should be a good choice instead of Oledb. 
  
 Any good news please let us know. 
  
 Regards, 
  
 Don