如何扫描 DynamoDB 以查找列表中的文本?
How to Scan DynamoDB for a text inside a list?
在 DynamoDB 中,我有一个具有以下结构的 table。
actions
"field" 包含所有信息(这是我要搜索的字段)并且 orderId
它是主键
{
"actions": [
{
"actionDescription": "8f23029def1d6baa4",
"actionTitle": "UNDEFINED_ACTION",
"timestamp": 1533730680,
"user": {
"fullName": "XXXXX",
"userName": "xxxxx@xxxx.xxx",
}
},
{
"actionDescription": "21857e61037bc29ec",
"actionTitle": "UNDEFINED_ACTION",
"timestamp": 1533731788,
"user": {
"fullName": "XXXXX",
"userName": "xxxxx@xxxx.xxx",
}
},
{
"actionDescription": "cf10abd44e24cef56",
"actionTitle": "UNDEFINED_ACTION",
"timestamp": 1533731788,
"user": {
"fullName": "XXXXX",
"userName": "xxxxx@xxxx.xxx",
}
},
{
"actionDescription": "7787fe7a5bf4d22de",
"actionTitle": "UNDEFINED_ACTION",
"timestamp": 1533731789,
"user": {
"fullName": "OOOOOO",
"userName": "ooooo@oooo.ooo",
}
},
{
"actionDescription": "9528c439021f504bf",
"actionTitle": "UNDEFINED_ACTION",
"timestamp": 1533731789,
"user": {
"fullName": "XXXXX",
"userName": "xxxxx@xxxx.xxx",
}
},
{
"actionDescription": "bfba100e0e54934b2",
"actionTitle": "UNDEFINED_ACTION",
"timestamp": 1533731789,
"user": {
"fullName": "XXXXX",
"userName": "xxxxx@xxxx.xxx",
}
},
{
"actionDescription": "f789dc12f1dbe3be2",
"actionTitle": "UNDEFINED_ACTION",
"timestamp": 1533731789,
"user": {
"fullName": "OOOOOO",
"userName": "ooooo@oooo.ooo",
}
},
{
"actionDescription": "4cd6b68dfea7cf8ee",
"actionTitle": "UNDEFINED_ACTION",
"timestamp": 1533731789,
"user": {
"fullName": "XXXXX",
"userName": "xxxxx@xxxx.xxx",
}
},
{
"actionDescription": "1e3a0e95f8e5106d7",
"actionTitle": "UNDEFINED_ACTION",
"timestamp": 1533731790,
"user": {
"fullName": "OOOOOO",
"userName": "ooooo@oooo.ooo",
}
}
],
"orderId": "13aae31"
}
我想做的是让 PHP 中的扫描词能够被 userName
搜索。或者通过动作数组中的任何字段(时间戳、actionTitle 等)。
下面是我尝试使用的众多术语之一,但我无法取得任何结果
$params = [
'TableName' => $this->tableName,
'FilterExpression' => "userName = :searchTerm",
'ExpressionAttributeValues' => [
':searchTerm' => 'ooooo@oooo.ooo',
],
'ReturnConsumedCapacity' => 'TOTAL',
];
$results = $this->dynamoDbClient->scan($params);
你能告诉我我缺少什么来指导我吗?
另外,请注意:我不想获得特定的 orderId
,我想获得包含 searchTerm 的所有 orderIds
(在本例中为 userName
)
使用此项目架构的最佳选择是自己过滤 table 项目。也就是说扫描没有过滤表达式的table,自己写代码过滤结果。没有过滤表达式的扫描将消耗相同数量的读取容量单位。
您可以将过滤器表达式设置为类似这样的内容,但是这不可扩展,并且仅当操作列表中的项目数量固定时才有效。
actions[0].user.userName == :searchTerm OR actions[1].user.userName == :searchTerm OR actions[2].user.userName == :searchTerm OR ....
如果您需要复杂的搜索功能,您最好使用专用的搜索数据库。 AWS 围绕这个提供了两种服务,AWS CloudSearch 和 AWS ElasticSearch。您可以使用 DynamoDB 流来使您的搜索索引保持最新。
如果您设置为使用过滤器扫描 DynamoDB table,您可以重构您的结构以包含其他属性,这些属性在一个集合(或串联字符串)中包含所有可搜索信息
{
"actions": [....],
"actionsDescriptions": Set["8f23029def1d6baa4", "21857e61037bc29ec", "cf10abd44e24cef56", "7787fe7a5bf4d22de", "9528c439021f504bf", "bfba100e0e54934b2", "f789dc12f1dbe3be2", "4cd6b68dfea7cf8ee", "1e3a0e95f8e5106d7"],
"actionTitles": Set["UNDEFINED_ACTION"],
"timestamps": Set[1533730680, 1533731788, 1533731789, 1533731790],
"user_fullNames": Set["XXXXX"],
"user_userNames": Set["ooooo@oooo.ooo", "xxxxx@xxxx.xxx"],
"orderId": "13aae31"
}
请注意,您必须使用集合(或将所有值连接成一个字符串),因为 contains
函数仅适用于字符串和集合。
然后你可以使用这样的过滤表达式
contains(user_userNames, :searchTerm)
DynamoDB QueryFilter
和 ScanFilter
选项当前不支持地图的 CONTAINS
运算符。您需要构建另一个由 userName
索引的查找 table 以避免扫描整个 table.
例如新 table 架构:
{
"userName": "xxxxx@xxxx.xxx"
"orderId": "13aae31"
}
其中散列键是userName
,orderId
是另一个table中的订单ID。
与当前架构最接近的是使用 @cementblocks 的建议来扫描整个 table 并过滤应用程序端或单独查询列表中的每个元素。
如果您要向应用程序添加类似 "Search" 的功能,那么扫描可能不是最佳方法。
DynamoDB 扫描成本高且速度慢,尤其是当您有很多行时。
因此,如果您打算添加 "Search" 功能,您可以考虑使用 AWS CloudSearch。这是一个可扩展的 "Search" 功能。您可以从 DynamoDB table.
快速启用 "Search"
在 DynamoDB 中,我有一个具有以下结构的 table。
actions
"field" 包含所有信息(这是我要搜索的字段)并且 orderId
它是主键
{
"actions": [
{
"actionDescription": "8f23029def1d6baa4",
"actionTitle": "UNDEFINED_ACTION",
"timestamp": 1533730680,
"user": {
"fullName": "XXXXX",
"userName": "xxxxx@xxxx.xxx",
}
},
{
"actionDescription": "21857e61037bc29ec",
"actionTitle": "UNDEFINED_ACTION",
"timestamp": 1533731788,
"user": {
"fullName": "XXXXX",
"userName": "xxxxx@xxxx.xxx",
}
},
{
"actionDescription": "cf10abd44e24cef56",
"actionTitle": "UNDEFINED_ACTION",
"timestamp": 1533731788,
"user": {
"fullName": "XXXXX",
"userName": "xxxxx@xxxx.xxx",
}
},
{
"actionDescription": "7787fe7a5bf4d22de",
"actionTitle": "UNDEFINED_ACTION",
"timestamp": 1533731789,
"user": {
"fullName": "OOOOOO",
"userName": "ooooo@oooo.ooo",
}
},
{
"actionDescription": "9528c439021f504bf",
"actionTitle": "UNDEFINED_ACTION",
"timestamp": 1533731789,
"user": {
"fullName": "XXXXX",
"userName": "xxxxx@xxxx.xxx",
}
},
{
"actionDescription": "bfba100e0e54934b2",
"actionTitle": "UNDEFINED_ACTION",
"timestamp": 1533731789,
"user": {
"fullName": "XXXXX",
"userName": "xxxxx@xxxx.xxx",
}
},
{
"actionDescription": "f789dc12f1dbe3be2",
"actionTitle": "UNDEFINED_ACTION",
"timestamp": 1533731789,
"user": {
"fullName": "OOOOOO",
"userName": "ooooo@oooo.ooo",
}
},
{
"actionDescription": "4cd6b68dfea7cf8ee",
"actionTitle": "UNDEFINED_ACTION",
"timestamp": 1533731789,
"user": {
"fullName": "XXXXX",
"userName": "xxxxx@xxxx.xxx",
}
},
{
"actionDescription": "1e3a0e95f8e5106d7",
"actionTitle": "UNDEFINED_ACTION",
"timestamp": 1533731790,
"user": {
"fullName": "OOOOOO",
"userName": "ooooo@oooo.ooo",
}
}
],
"orderId": "13aae31"
}
我想做的是让 PHP 中的扫描词能够被 userName
搜索。或者通过动作数组中的任何字段(时间戳、actionTitle 等)。
下面是我尝试使用的众多术语之一,但我无法取得任何结果
$params = [
'TableName' => $this->tableName,
'FilterExpression' => "userName = :searchTerm",
'ExpressionAttributeValues' => [
':searchTerm' => 'ooooo@oooo.ooo',
],
'ReturnConsumedCapacity' => 'TOTAL',
];
$results = $this->dynamoDbClient->scan($params);
你能告诉我我缺少什么来指导我吗?
另外,请注意:我不想获得特定的 orderId
,我想获得包含 searchTerm 的所有 orderIds
(在本例中为 userName
)
使用此项目架构的最佳选择是自己过滤 table 项目。也就是说扫描没有过滤表达式的table,自己写代码过滤结果。没有过滤表达式的扫描将消耗相同数量的读取容量单位。
您可以将过滤器表达式设置为类似这样的内容,但是这不可扩展,并且仅当操作列表中的项目数量固定时才有效。
actions[0].user.userName == :searchTerm OR actions[1].user.userName == :searchTerm OR actions[2].user.userName == :searchTerm OR ....
如果您需要复杂的搜索功能,您最好使用专用的搜索数据库。 AWS 围绕这个提供了两种服务,AWS CloudSearch 和 AWS ElasticSearch。您可以使用 DynamoDB 流来使您的搜索索引保持最新。
如果您设置为使用过滤器扫描 DynamoDB table,您可以重构您的结构以包含其他属性,这些属性在一个集合(或串联字符串)中包含所有可搜索信息
{
"actions": [....],
"actionsDescriptions": Set["8f23029def1d6baa4", "21857e61037bc29ec", "cf10abd44e24cef56", "7787fe7a5bf4d22de", "9528c439021f504bf", "bfba100e0e54934b2", "f789dc12f1dbe3be2", "4cd6b68dfea7cf8ee", "1e3a0e95f8e5106d7"],
"actionTitles": Set["UNDEFINED_ACTION"],
"timestamps": Set[1533730680, 1533731788, 1533731789, 1533731790],
"user_fullNames": Set["XXXXX"],
"user_userNames": Set["ooooo@oooo.ooo", "xxxxx@xxxx.xxx"],
"orderId": "13aae31"
}
请注意,您必须使用集合(或将所有值连接成一个字符串),因为 contains
函数仅适用于字符串和集合。
然后你可以使用这样的过滤表达式
contains(user_userNames, :searchTerm)
DynamoDB QueryFilter
和 ScanFilter
选项当前不支持地图的 CONTAINS
运算符。您需要构建另一个由 userName
索引的查找 table 以避免扫描整个 table.
例如新 table 架构:
{
"userName": "xxxxx@xxxx.xxx"
"orderId": "13aae31"
}
其中散列键是userName
,orderId
是另一个table中的订单ID。
与当前架构最接近的是使用 @cementblocks 的建议来扫描整个 table 并过滤应用程序端或单独查询列表中的每个元素。
如果您要向应用程序添加类似 "Search" 的功能,那么扫描可能不是最佳方法。
DynamoDB 扫描成本高且速度慢,尤其是当您有很多行时。
因此,如果您打算添加 "Search" 功能,您可以考虑使用 AWS CloudSearch。这是一个可扩展的 "Search" 功能。您可以从 DynamoDB table.
快速启用 "Search"