Reverse geocoding with big array is fastest way? - javascript and performance

前端 未结 4 1043
终归单人心
终归单人心 2021-01-07 00:30

I have many points on Google Maps and I want to show for each point the nearest city (so a reverse geocoding). I have a multidimensional array like this:

相关标签:
4条回答
  • 2021-01-07 00:36

    To get nearest city...

    If you're only interested in the nearest city, you don't need to sort the whole list. That's your first performance gain in one line of code!

    // Unneeded sort:
    const closest = cityDistancePairs.sort((a, b) => a[1] - b[2])[0];
    
    // Only iterates once instead:
    const closestAlt = cityDistancePairs.reduce(
      (closest, current) => current[1] < closest[1] ? current : closest
    );
    

    To further optimize you'll need to benchmark which parts of the code take the longest to run. Some ideas:

    • Do a quick check on the lat/lon difference before calculating the precise value. If coordinates are further than a certain delta apart, you already know they are out of range.
    • Cache the calculated distances by implementing a memoization pattern to make sure that on a second pass with a different limit (50 -> 100), you don't recalculate the distances

    However, I can't imagine that a loop of 8000 distance calculations is the real performance drain... I'm guessing that the parsing of 300kb of javascript is the real bottleneck. How are you initializing the city array?

    Make sure you strip down the data set to only the properties and values you actually use. If you know you're only going to use the name and lat/lon, you can preprocess the data to only include those. That'll probably make it much smaller than 300kb and easier to work with.

    0 讨论(0)
  • 2021-01-07 00:37

    You may want to sort after the second array element:

     citta_vicine.sort(function(a, b) {
       return a[1] - b[1];
     }); 
    
    0 讨论(0)
  • 2021-01-07 00:47

    Since the city data is not dynamically changed and you need to calculate the distance / nearest neighbour frequently, using a geospatial index (KD-Tree, R-Tree etc) would make sense.

    Here's an example implementation using geokdbush which is based on a static spatial index implemented using a KD-Tree. It takes Earth curvature and date line wrapping into account.

    const kdbush = require('kdbush');
    const geokdbush = require('geokdbush');
    
    // I've stored the data points as objects to make the values unambiguous
    const cities = [
      { name: "Abano Terme (PD)", latitude: 45.3594, longitude: 11.7894 },
      { name: "Abbadia Cerreto (LO)", latitude: 45.3122, longitude: 9.5928 },
      { name: "Abbadia Lariana (LC)", latitude: 45.8992, longitude: 9.3336 },
      { name: "Abbadia San Salvatore (SI)", latitude: 42.8800, longitude: 11.6775 },
      { name: "Abbasanta (OR)", latitude: 40.1250, longitude: 8.8200 }
    ];
    
    // Create the index over city data ONCE
    const index = kdbush(cities, ({ longitude }) => longitude, ({ latitude }) => latitude);
    
    // Get the nearest neighbour in a radius of 50km for a point with latitude 43.7051 and longitude 11.4363
    const nearest = geokdbush.around(index, 11.4363, 43.7051, 1, 50);
    

    Once again, bear in mind that kdbush is a static index and cannot be changed (you cannot add or remove cities from it). If you need to change the city data after initialisation, depending on how often you do it, using an index might prove too costly.

    0 讨论(0)
  • 2021-01-07 00:51

    0 讨论(0)
提交回复
热议问题