Redis SCAN命令模式匹配NOT运算符及匹配失效问题咨询
Hey there! Let's unpack your Redis SCAN questions and get to the bottom of what's happening here.
First: Why Your Current Patterns Work (or Don't)
First off, it's critical to remember that Redis' SCAN MATCH parameter uses glob-style pattern matching, not full regular expressions. That's the root of why your two patterns behave so differently:
1. SCAN 0 MATCH trip:*[^:routes] (Seems to Work)
This pattern isn't actually excluding keys ending with :routes—it's just a happy coincidence given your current key set. Here's what it really does:
trip:*matches any key starting withtrip:[^:routes]matches a single character that is NOT one of:,r,o,u,t,e, ors
Since your main trip key is trip:1734 (ends with 4, which isn't in that excluded set) and your route key is trip:1734:routes (ends with s, which is in the excluded set), this pattern filters out the route key. But this is fragile: if you had a valid trip key ending with e or r, it would get incorrectly filtered out. This pattern isn't reliable for your actual goal.
2. SCAN 0 MATCH trip:*[^:*] (Doesn't Work)
This pattern tries to exclude keys with :* at the end, but glob logic gets in the way:
[^:*]matches a single character that is NOT:or*
Both your keys trip:1734 (ends with 4) and trip:1734:routes (ends with s) pass this check—neither ends with : or *—so both get matched. That's why it fails to exclude the route key.
The Real Problem: Redis SCAN Has No Built-in NOT Operator
Unfortunately, Redis' glob pattern matching for SCAN doesn't include a proper NOT operator to exclude entire suffixes or patterns. The [^...] syntax only works for single characters, not multi-character strings.
How to Properly Get Trip Keys Without Routes
You have a few reliable options to achieve your goal:
Option 1: Client-Side Filtering
Scan all trip:* keys, then filter out the ones ending with :routes in your application code. For example, in Python:
import redis r = redis.Redis() cursor = 0 while True: cursor, keys = r.scan(cursor, match='trip:*') for key in keys: if not key.endswith(b':routes'): # Adjust based on your language's string handling print(key) if cursor == 0: break
This is straightforward and works regardless of your trip key naming format.
Option 2: Use a More Precise Glob Pattern (If Possible)
If your main trip keys follow a strict format (like trip:[0-9]+), you can match directly against that pattern:
SCAN 0 MATCH trip:[0-9]*
This works only if all non-route trip keys fit this format—if you have keys like trip:nyc-central, this won't help.
Option 3: Maintain a Dedicated Set of Main Trip Keys
For better performance (especially with large key spaces), create a Redis Set that tracks all your main trip keys. When you create a trip key like trip:1734, add it to the set:
SADD trip:main_keys trip:1734
Then, to get all main trip keys, just scan or fetch from this set:
SSCAN 0 MATCH * # Or SMEMBERS if the set is small
This avoids scanning all trip:* keys entirely and is the most efficient approach for large-scale use.
Key Takeaways
- Redis
SCANuses glob patterns, not regex—forget about regex-style negative lookaheads or full string negation. - The
[^...]syntax only excludes single characters, not multi-character suffixes. - To exclude specific key patterns, use client-side filtering or maintain a dedicated index set for your main keys.
内容的提问来源于stack exchange,提问作者cybercoder

