如何在PHP中实现DynamoDB的通配符搜索?
Hey there! I totally get the frustration—DynamoDB doesn’t have a direct equivalent to SQL’s LIKE wildcard, and the official docs can be a bit sparse on practical PHP examples. Let’s walk through how to replicate common wildcard search patterns while working with your existing filter expression.
1. Prefix Matching (foo*)
If you need to match strings that start with a specific prefix (like usernames starting with "joh" or titles starting with "2024-"), use DynamoDB’s begins_with() function. This plays nicely with efficient queries if you’re already targeting a partition key.
Here’s how to add this to your existing logic:
use Aws\DynamoDb\DynamoDbClient; // Initialize your DynamoDB client $client = new DynamoDbClient([ 'region' => 'your-region', 'version' => 'latest' ]); $queryParams = [ 'TableName' => 'your-table-name', // Use KeyConditionExpression if userId is your partition key (way more efficient than Scan) 'KeyConditionExpression' => 'userId = :v1', 'FilterExpression' => 'entryStamp between :v2 and :v3 AND begins_with(title, :v4)', 'ExpressionAttributeValues' => [ ':v1' => ['S' => 'user123'], ':v2' => ['N' => '1620000000'], // Start timestamp ':v3' => ['N' => '1630000000'], // End timestamp ':v4' => ['S' => '2024-Q1-'] // Your desired prefix ] ]; // Run the query and process results $result = $client->query($queryParams); foreach ($result['Items'] as $item) { // Handle each matched item here }
2. Contains Matching (*foo*)
For cases where you need to find strings that include a specific substring anywhere (like searching for "error" in a log description), use the contains() function.
Example modification to your filter:
$scanParams = [ 'TableName' => 'your-table-name', 'FilterExpression' => 'userId = :v1 AND entryStamp between :v2 and :v3 AND contains(description, :v4)', 'ExpressionAttributeValues' => [ ':v1' => ['S' => 'user123'], ':v2' => ['N' => '1620000000'], ':v3' => ['N' => '1630000000'], ':v4' => ['S' => 'timeout'] // Substring to match ] ]; // Note: Scan is less efficient—use a GSI if you can narrow results first $result = $client->scan($scanParams);
3. Suffix Matching (*foo)
DynamoDB doesn’t have a built-in suffix match function, but we can work around this by storing a reversed version of the target field (e.g., title_reversed alongside title). Then we use begins_with() on the reversed field with a reversed suffix.
Step 1: Store reversed data when writing items
$originalTitle = "report-final.pdf"; $reversedTitle = strrev($originalTitle); // Becomes "fdp.lanim-troper" $client->putItem([ 'TableName' => 'your-table-name', 'Item' => [ 'userId' => ['S' => 'user123'], 'title' => ['S' => $originalTitle], 'title_reversed' => ['S' => $reversedTitle], 'entryStamp' => ['N' => '1625000000'] ] ]);
Step 2: Query using the reversed suffix
$targetSuffix = ".pdf"; $reversedSuffix = strrev($targetSuffix); // Becomes "fdp." $queryParams = [ 'TableName' => 'your-table-name', 'KeyConditionExpression' => 'userId = :v1', 'FilterExpression' => 'entryStamp between :v2 and :v3 AND begins_with(title_reversed, :v4)', 'ExpressionAttributeValues' => [ ':v1' => ['S' => 'user123'], ':v2' => ['N' => '1620000000'], ':v3' => ['N' => '1630000000'], ':v4' => ['S' => $reversedSuffix] ] ]; $result = $client->query($queryParams);
Key Tips for Performance
- Prioritize
QueryoverScan:Scanreads every item in your table, which is slow for large datasets. UseQuerywith a partition key or GSI to narrow results first. - Use GSIs for frequent searches: If you regularly search a specific field, create a Global Secondary Index (GSI) with that field as the sort key to cut down on filtering time.
- Advanced full-text needs: For complex wildcard or full-text search, consider integrating Amazon OpenSearch Service with DynamoDB (you can set up triggers to sync data automatically).
内容的提问来源于stack exchange,提问作者Saurabh Sharma

