redis - guia - qgis manual
¿Cómo utilizar la búsqueda de proximidad de Redis y geo para encontrar dos usuarios en la misma ubicación? (7)
En general, esto se puede hacer mediante el conjunto ordenado de GeoHash y Redis. Hay un diseño que escribí antes de hablar sobre cómo implementar un servicio de índice espacial en redis.
Quiero implementar un servicio que, dadas las coordenadas geográficas de los usuarios, pueda detectar si dos usuarios se encuentran en la misma ubicación en tiempo real.
Para hacer esto en tiempo real y para escalar, parece que debo ir con un almacén de datos en memoria distribuido como Redis. He investigado el uso de geohashing, pero el problema es que los puntos cercanos no siempre comparten el mismo prefijo hash. Y el geohashing puede ser una exageración ya que me interesa saber si dos usuarios están lo suficientemente cerca de donde están parados uno al lado del otro.
La solución simple, por supuesto, es solo probar si los pares de coordenadas geográficas se encuentran dentro de una pequeña distancia entre sí. Pero AFAIK, Redis y otros datos en memoria no tienen indexación geoespacial para soportar ese tipo de búsqueda.
¿Cuál es la mejor manera de implementar esto?
Esta funcionalidad está integrada en Redis 3.2+ .
Pero para versiones anteriores el problema todavía existe. Tomé la respuesta de Yin Qiwen y creé un módulo para Node, y puedes ver cómo usa Redis examinando el código. Sus instrucciones son perfectas y pude seguirlas para obtener excelentes resultados. https://github.com/arjunmehta/node-georedis
El mismo algoritmo es esencialmente lo que se usa para los comandos nativos.
Es muy rápido, y evita cualquier tipo de intersecciones / operaciones de tipo haversine. Lo mejor (creo) sobre el método de Yin Qiwen es que las partes más computacionalmente intensas del algoritmo se pueden distribuir a los clientes (en lugar de que todo suceda en la base de datos o en el servidor).
No es 100% preciso y utiliza pasos de distancia preconfigurados, pero para la mayoría de las aplicaciones no necesitará la precisión exacta que imagino.
También he parafraseado el artículo de Yin Qiwen en el intercambio de pila GIS .
Lo siento por todo el enlace. :PAG
La base de datos de Tarantool mantiene los datos en la memoria, los inserta en el disco como registros de transacciones, tiene un índice espacial de tipo RTree (no solo bidimensional) y una serie de buenas operaciones en dicho índice (contención, superposición, distancia).
Lo uso en un proyecto comercial para almacenar y consultar registros que describen objetos en un espacio 3D.
http://tarantool.org/doc/book/box/box_index.html
https://github.com/tarantool/tarantool/wiki/R-tree-index-quick-start-and-usage
El cliente estándar y los ejemplos están en Lua, pero hay otros dos clientes desarrollados por los autores de la base de datos. Utilizo el cliente Java en una aplicación Scala con éxito.
La base de datos también es muy rápida; aquí hay una comparación científica con otras bases de datos (dejando de lado un aspecto de ser una base de datos espacial): http://airccse.org/journal/ijdms/papers/6314ijdms01.pdf
La edición de la geografía de Redis mencionada por otras respuestas en este hilo se ha integrado en Redis desde la versión 3.2 (vea también este comentario anterior ).
Puedes encontrar los nuevos comandos aquí (en beta por ahora):
Me doy cuenta de que esto no responde a tu pregunta ... pero no creo que sea la herramienta correcta.
PostgreSQL + PostGIS puede funcionar realmente bien. Puede configurar PostgreSQL para ejecutar prácticamente la mayor parte de la base de datos que pueda caber en la memoria.
PostGIS usa (creo) índices de rtree, por lo que es increíblemente rápido para realizar el tipo de búsqueda que le interesa.
El uso de un backend que dispara las solicitudes de websocket le permitiría realizar casi en tiempo real. En cualquier momento su backend recibe una persona con coordenadas GPS; realizar la búsqueda espacial; y notificar a los clientes aplicables a través de websockets.
Me gustaría compartir un código Java de muestra para la edición de Geografía de Redis.
public void geoadd(String objectId, BigDecimal latitude, BigDecimal longitude) {
log.info("geoadd(): {} {} {}", objectId, latitude, longitude);
try (Jedis jedis = jedisPool.getResource()) {
if (geoaddSha == null) {
String script = "return redis.call(''geoadd'',''" + GEOSET + "'', ARGV[1], ARGV[2], KEYS[1])";
geoaddSha = jedis.scriptLoad(script);
}
log.info("geoaddSha: {}", geoaddSha);
log.info(jedis.evalsha(geoaddSha, 1, objectId, latitude.toString(), longitude.toString()).toString());
}
}
@SuppressWarnings("unchecked")
public List<String> georadius(BigDecimal latitude, BigDecimal longitude, int radius, Unit unit) {
log.info("georadius(): {} {} {} {}", latitude, longitude, radius, unit);
try (Jedis jedis = jedisPool.getResource()) {
if (georadiusSha == null) {
String script = "return redis.call(''georadius'',''" + GEOSET + "'', ARGV[1], ARGV[2], ARGV[3], ARGV[4])";
georadiusSha = jedis.scriptLoad(script);
}
log.info("georadiusSha: {}", georadiusSha);
List<String> objectIdList = (List<String>) jedis.evalsha(georadiusSha, 0, latitude.toString(), longitude.toString(), String.valueOf(radius), unit.toString());
log.info("objectIdList: {}", objectIdList);
return objectIdList;
}
}
public void remove(String objectId) {
log.info("remove(): {}", objectId);
try (Jedis jedis = jedisPool.getResource()) {
jedis.zrem(GEOSET, objectId);
}
}
Quizás puedas probar este:
Realmente quieres probarlo, funciona genial. :)