Как Geofire вычисляет ограничивающие геохэши для запросов Firebase?

Контекст

Я некоторое время использовал Geofire вместе с Firebase, и мне стало очень любопытно, как Geofire выполняет свои запросы. Я понимаю, что семантически это функция координат и радиуса, которая приводит к минимальному и максимальному хэшам. То, как я думаю, что это работает в сочетании с Firebase, будет выглядеть так:

ref.child("users").orderByChild("g").startAt(minHash).endAt(maxHash).on('child_added', function(snapshot) { /* retrieved snapshot contains the geohashes in range */ });

Где эти два геохеша (минимум и максимум) рассчитываются на основе заданных входных данных. Теперь вот вопрос

Вопрос(ы)

Предполагая, что то, что я сказал выше, верно, как рассчитываются эти два геохэша? Как они возвращают результаты в определенной круглой области, когда геохэши обычно представляют ограничивающие прямоугольники? И, наконец, как два геохеша разного размера могут иметь один и тот же центр?

Чтобы уточнить последнюю часть: рассмотрите следующее изображение

Обычные этапы геохеширования

Поскольку геохеширование работает путем деления регионов пополам на более мелкие регионы, как два хеша разного размера (минимум и максимум) могут иметь одинаковые центральные точки?

Предположения

Я думал, что, возможно, это так же просто, как увеличение/уменьшение необработанного значения хеша, но это не имеет особого смысла, поскольку увеличение/уменьшение должно быть относительно размера хеша (так сказать, уровень «масштабирования») и радиус запроса, если не ошибаюсь.


person ThunderStruct    schedule 12.02.2017    source источник


Ответы (1)


GeoFire фактически выполняет запрос диапазона прямоугольной области к базе данных. Этот диапазон представляет собой наименьший прямоугольник, охватывающий диапазон, указанный в запросе.

Затем в клиентском коде проверяется фактическое расстояние от каждой клавиши до центра запроса и инициируется событие key_entered/key_moved только для элементов внутри запроса.

Соответствующий код находится здесь:

// Determine if the location is within this query
distanceFromCenter = GeoFire.distance(location, _center);
isInQuery = (distanceFromCenter <= _radius);

...

// Fire the "key_entered" event if the provided key has entered this query
if (isInQuery && !wasInQuery) {
  _fireCallbacksForKey("key_entered", key, location, distanceFromCenter);
} else if (isInQuery && oldLocation !== null && (location[0] !== oldLocation[0] || location[1] !== oldLocation[1])) {
  _fireCallbacksForKey("key_moved", key, location, distanceFromCenter);
} else if (!isInQuery && wasInQuery) {
  _fireCallbacksForKey("key_exited", key, location, distanceFromCenter);
}
person Frank van Puffelen    schedule 14.02.2017