基于位置的 AWS AppSync 事件订阅
AWS AppSync Event Subscription based on Location
我了解如何通过 AppSync
执行地理空间查询,通过附加链接到 ElasticSesarch
的解析器来查找距 gps 坐标一定距离范围内的事件,如 described here。
但是,如果我希望我的客户也订阅在此距离范围内创建的新事件怎么办?
- 用户订阅了一个位置
- 如果在该位置附近创建了事件,请通知用户
我知道我可以将解析器附加到订阅类型,但当我只想通过检查 gps 坐标之间的距离来过滤订阅时,它似乎强制你提供数据源。
这是一个很好的问题,我认为有几种方法可以解决这个问题。这里最困难的部分是您将找到一种提出问题 "What subscriptions are interested in an event at this location" 的方法。这是一条可能的前进道路。
以下假定这些架构部分:
// 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 作为主要的真实来源,请设置调用 "PublishIfInRange" lambda 函数的 DynamoDB 流。 "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,该 mutation 创建一个具有位置和 subscriptionID 的订阅对象(例如 mutation { makeSubscription(loc: $loc) { ... } }
假设您正在使用 $util.autoId() 在解析器中生成 subscriptionID ).获得 subscriptionID 后,您可以通过 graphql 进行订阅调用,并将 subscriptionID 作为参数传入(例如 subscription { listenToSubscription(subscriptionID: "my-id") { id title location { lat lon } } }
)。当您进行上述订阅调用时,AppSync 会创建一个主题并授权当前用户订阅该主题。该主题对于被调用的订阅字段和传递给订阅字段的参数集是唯一的。也就是说topic只接收objects
现在,无论何时创建对象,记录都会通过 DynamoDB 流进入 lambda 函数。 lambda 函数在 elasticsearch 中查询该对象附近的所有开放订阅,然后向每个开放订阅发布一条记录。
我相信这应该会让你走得更远,但如果你在狭小的空间内拥有数百万用户,你可能 运行 会遇到扩展问题。希望这有帮助
我了解如何通过 AppSync
执行地理空间查询,通过附加链接到 ElasticSesarch
的解析器来查找距 gps 坐标一定距离范围内的事件,如 described here。
但是,如果我希望我的客户也订阅在此距离范围内创建的新事件怎么办?
- 用户订阅了一个位置
- 如果在该位置附近创建了事件,请通知用户
我知道我可以将解析器附加到订阅类型,但当我只想通过检查 gps 坐标之间的距离来过滤订阅时,它似乎强制你提供数据源。
这是一个很好的问题,我认为有几种方法可以解决这个问题。这里最困难的部分是您将找到一种提出问题 "What subscriptions are interested in an event at this location" 的方法。这是一条可能的前进道路。
以下假定这些架构部分:
// 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 作为主要的真实来源,请设置调用 "PublishIfInRange" lambda 函数的 DynamoDB 流。 "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,该 mutation 创建一个具有位置和 subscriptionID 的订阅对象(例如 mutation { makeSubscription(loc: $loc) { ... } }
假设您正在使用 $util.autoId() 在解析器中生成 subscriptionID ).获得 subscriptionID 后,您可以通过 graphql 进行订阅调用,并将 subscriptionID 作为参数传入(例如 subscription { listenToSubscription(subscriptionID: "my-id") { id title location { lat lon } } }
)。当您进行上述订阅调用时,AppSync 会创建一个主题并授权当前用户订阅该主题。该主题对于被调用的订阅字段和传递给订阅字段的参数集是唯一的。也就是说topic只接收objects
现在,无论何时创建对象,记录都会通过 DynamoDB 流进入 lambda 函数。 lambda 函数在 elasticsearch 中查询该对象附近的所有开放订阅,然后向每个开放订阅发布一条记录。
我相信这应该会让你走得更远,但如果你在狭小的空间内拥有数百万用户,你可能 运行 会遇到扩展问题。希望这有帮助