Я понимаю, как выполнять геопространственные запросы через AppSync для поиска событий в диапазоне расстояний от координаты GPS, подключив преобразователь, связанный с ElasticSesarch, как описано здесь.
Однако что, если я хочу, чтобы мой клиент подписался на новые события, создаваемые в пределах этого диапазона расстояний?
Я знаю, что могу прикрепить преобразователь к типам подписок, но похоже, что он заставляет вас предоставлять источник данных, когда я просто хочу фильтровать подписки, проверяя расстояние между координатами GPS.





Это отличный вопрос, и я думаю, что есть несколько способов его решить. Сложность здесь в том, что вам нужно придумать способ задать вопрос «Какие подписки заинтересованы в мероприятии в этом месте». Вот один из возможных путей вперед.
Следующее предполагает эти части схемы:
// Whatever custom object has a location
type Post {
id: ID!
title: String
location: Location
}
input PublishPostInput {
id: ID!
title: String
location: Location
subscriptionID: ID
}
type PublishPostOutput {
id: ID!
title: String
location: Location
subscriptionID: ID
}
type Location {
lat: Float,
lon: Float
}
input LocationInput {
lat: Float,
lon: Float
}
# A custom type to hold custom tracked subscription information
# for location discover
type OpenSubscription {
subscriptionID: ID!
location: Location
timestamp: String!
}
type OpenSubscriptionConnection {
items: [OpenSubscription]
nextToken: String
}
type Query {
# Query elasticsearch index for relevant subscriptions
openSubscriptionsNear(location: LocationInput, distance: String): OpenSubscriptionConnection
}
type Mutation {
# This mutation uses a local resolver (e.g. a resolver with a None data source) and simply returns the input as is.
publishPostToSubscription(input: PublishPostInput): PublishPostOutput
}
type Subscription {
# Anytime someone passes an object with the same subscriptionID to the "publishPostToSubscription" mutation field, get updated.
listenToSubscription(subscriptionID: ID!): PublishPostOutput
@aws_subscribe(mutations:["publishPostToSubscription"])
}
Предполагая, что вы используете DynamoDB в качестве основного источника истины, настройте поток DynamoDB, который вызывает лямбда-функцию PublishIfInRange. Эта функция PublishIfInRange будет выглядеть примерно так
// event - { location: { lat, lon }, id, title, ... }
function lambdaHandler(event) {
const relevantSubscriptions = await callGraphql(`
query GetSubscriptions($location: LocationInput) {
openSubscriptionsNear(location:$location, distance: "10 miles") {
subscriptionID
}
}
`, { variables: { location: event.location }})
for (const subscription of relevantSubscriptions) {
callGraphql(`
mutation PublishToSubscription($subID: ID!, $obj: PublishPostInput) {
publishPostToSubscription(input: $obj) {
id
title
location { lat lon }
subscriptionID
}
}
`, { variables: { input: { ...subscription, ...event }}})
}
}
Вам нужно будет вести реестр подписок, индексированных по местоположению. Один из способов сделать это - заставить ваше клиентское приложение вызывать мутацию, которая создает объект подписки с местоположением и идентификатором подписки (например, mutation { makeSubscription(loc: $loc) { ... } }, если вы используете $ util.autoId () для генерации идентификатора подписки в преобразователе). После того, как у вас есть идентификатор подписки, вы можете выполнить вызов подписки через graphql и передать идентификатор подписки в качестве аргумента (например, subscription { listenToSubscription(subscriptionID: "my-id") { id title location { lat lon } } }). Когда вы делаете этот вызов подписки выше, AppSync создает тему и разрешает текущему пользователю подписаться на эту тему. Тема уникальна для вызываемого поля подписки и набора аргументов, передаваемых в поле подписки. Другими словами, тема получает только объекты
Теперь всякий раз, когда создается объект, запись передается в лямбда-функцию через потоки DynamoDB. Лямбда-функция запрашивает у elasticsearch все открытые подписки рядом с этим объектом, а затем публикует запись для каждой из этих открытых подписок.
Я считаю, что это должно продвинуть вас достаточно далеко, но если у вас миллионы пользователей в ограниченном пространстве, вы, вероятно, столкнетесь с проблемами масштабирования. Надеюсь это поможет
Учитывая проблему масштабирования и стоимость обслуживания многих каналов подписки со стороны пользователя, не будет ли разумнее просто запрашивать чаще, чтобы убедиться, что пользователь обновляется почти в реальном времени?
Опрос - гораздо более простой и экономичный вариант, если истинный режим реального времени не является обязательным требованием.
Чтобы масштабировать это, вы можете лучше понять, как разделить subscriptionID. Например, вы можете разбить свою карту на N небольших фрагментов, а затем на вашем клиенте попросить их подписаться на Y ближайших фрагментов в сетке и выполнить любую мелкую фильтрацию на клиенте. Таким образом, у вас будет не более N идентификаторов подписки, поэтому процесс разветвления будет намного меньше, чем если бы у каждого пользователя была собственная подписка.