如何高效搜索Python嵌套字典?21000条数据提速方案
优化方案:预构建反向索引
由于你的数据是启动时加载完成、运行期只读的,最有效的优化方式是预构建反向索引表,把每个属性键、属性键值对映射到对应的职业列表,这样搜索时直接通过索引查询,不需要遍历全量21000条数据。
1. 构建两种核心索引
- 属性存在索引:记录包含某个属性(如
crime)的所有职业 - 属性键值对索引:记录某个属性等于特定值(如
crime="high")的所有职业
代码实现
test_data = { "hacker": {"crime": "high"}, "mugger": {"crime": "high", "morals": "low"}, "shop_owner": {"crime": "high", "morals": "high"}, "office_drone": {"work_drive": "high", "tolerance": "high"}, "farmer": {"work_drive": "high"}, } class OptimizedConditional: def __init__(self, data): self.dataset = data # 预构建索引 self.attr_exists_index = {} # key: 属性名, value: 职业列表 self.attr_value_index = {} # key: (属性名, 属性值), value: 职业列表 for job, attrs in data.items(): # 处理属性存在索引 for attr in attrs: if attr not in self.attr_exists_index: self.attr_exists_index[attr] = [] self.attr_exists_index[attr].append(job) # 处理属性键值对索引 for attr, val in attrs.items(): key = (attr, val) if key not in self.attr_value_index: self.attr_value_index[key] = [] self.attr_value_index[key].append(job) def find(self, *required_attrs, **tag_filters): # 先处理必填属性的交集 result_set = None if required_attrs: try: result_set = set(self.attr_exists_index[required_attrs[0]]) for attr in required_attrs[1:]: result_set.intersection_update(self.attr_exists_index[attr]) except KeyError: # 某个必填属性不存在,直接返回空列表 return [] # 处理键值对过滤 if tag_filters: filter_sets = [] for attr, val in tag_filters.items(): key = (attr, val) if key not in self.attr_value_index: return [] filter_sets.append(set(self.attr_value_index[key])) # 计算所有过滤条件的交集 filter_result = set(filter_sets[0]) for s in filter_sets[1:]: filter_result.intersection_update(s) # 和必填属性的结果取交集 if result_set is not None: result_set.intersection_update(filter_result) else: result_set = filter_result # 处理无过滤条件的情况 if result_set is None: return list(self.dataset.keys()) return list(result_set) # 测试 jobs = OptimizedConditional(test_data) print(jobs.find(work_drive="high")) >>> ['office_drone', 'farmer'] print(jobs.find("crime")) >>> ['hacker', 'mugger', 'shop_owner'] print(jobs.find("crime", "morals")) >>> ['mugger', 'shop_owner'] print(jobs.find("crime", morals="high")) >>> ['shop_owner']
2. 效率提升的核心原因
- 时间复杂度优化:原方法每次搜索是O(N)(N为职业总数),预索引后搜索是O(K)(K为结果集大小),对于21000条数据的场景,多次搜索的效率提升非常显著。
- 集合操作的底层优化:Python的集合交集操作是C实现的,比手动遍历判断快数倍。
- 只读数据的优势:索引仅在启动时构建一次,后续搜索直接复用,无额外开销。
3. 额外小优化
- 提前将职业列表转为集合,进一步加速交集运算。
- 对不存在的属性/键值对直接返回空列表,避免无效计算。
- 若后续需要支持模糊搜索,可扩展使用前缀树(Trie)或倒排索引,但当前精确匹配场景下,上述索引已足够。
内容的提问来源于stack exchange,提问作者Dimsey
相关产品推荐
相关产品推荐

