Google Earth Engine – Get Random Image for Each Point Without Exceeding GEE User Memory Limit

google-earth-enginegoogle-earth-engine-javascript-api

For a collection of points, I want to randomly select one image over each point.

My naive approach (see below) was to map a function that filters the collection to that point, and then selects an image, but I quickly ran into user memory errors.

How can I get one random image per point?

// Make random points
var nPts = 100
var randomPts = ee.FeatureCollection.randomPoints(geometry, nPts, 123, 10)
Map.addLayer(randomPts)


// Function to get random image for a point
var getBandData = function(feat){
  var point = ee.Geometry(feat.geometry())

  // Get a random image for this point
  var img = s2sr
    .filterBounds(point)
    .randomColumn('random', 123)
    .sort('random')
    .first()
  
  return img
}

print( randomPts.map(getBandData) ) // Error: user memory limit exceeded

https://code.earthengine.google.com/?scriptPath=users%2Fcaseyengstrom%2Freprex%3ArandomImages

Best Answer

The short answer is "it's the 100 sorts". You can work around it by doing a reduceColumns instead of a sort, with a max() reducer using the numInputs option to bring along the image ID that goes with the maximum random number. (Yes, it's a little screwy, but sorting ends up needing the whole collection in memory at once and reduceColumns does not.)

// For each point, get a random image
var getBandData = function(feat){
  var point = ee.Geometry(feat.geometry())

  // Get a random image for this point
  var result = s2sr
    .filterBounds(point)
    .randomColumn('random', 123)
    .reduceColumns(ee.Reducer.max(2), ['random', 'system:index'])
  return s2sr.filter(ee.Filter.eq('system:index', result.get('max1')))
}

https://code.earthengine.google.com/bdd36facac25401263fc9812596bf473