【问题标题】:Comparing two large lists and fetching the matched results比较两个大列表并获取匹配的结果
【发布时间】:2020-07-06 11:25:46
【问题描述】:

我试图寻找这个很多,但找不到合适的解决方案。我有两个大的字符串列表,每个列表有 150 万条记录。这两个列表都在不同列的 where 子句内的 SQL 查询中传递。 例如:Select * from TBL1 where FOO IN (Col1_List) and BAR IN (Col2_list);

由于 SQL 中 IN Clause 内的某些 lambda 限制不支持超过 16K 的值,我想每次都传递有限的值进行处理,请考虑以下示例:

Col1_list = ['1_a_title','2_title','3_b_title','4_c_title','5_title']  #  and so on ..
Col2_list = ['1_a','2','3_b','4_c','5']  # and so on..

如您所见,Col1_listCol2_list 相比,每个值都包含一些额外的字符(比如_title)。两个列表都以整数开头,并且这些整数可能附加了一些其他字符(例如 1_a, 3_b)。

目标:我想在 IN 子句中传递 16K 值,因此整数部分 Col1_listCol2_list 必须匹配才能产生正确的 sql 结果。我尝试了以下代码:

方法 1: - 循环 Col2_list 并匹配它以创建一个新的匹配记录列表:

for i in range(0, len(Col2_list), 16000):
    chunk = Col2_list[i:i + 16000]
    new_kl = []
    for val_to_check in chunk:
      print(val_to_check)
      new_kl.append([item1 for item1 in Col1_list if val_to_check.split('_')[0] == item1.split('_')[0]])
      print(val_to_check + " - " + str(new_kl))
    <Do Processing for obtained 16K values>

方法 2: 用 For comprehension 尝试了同样的方法

for i in range(0, len(Col2_list), 16000):
    chunk = Col2_list[i:i + 16000]
    matched_list = [item for x in chunk for item in Col1_list if item.split('_')[0] == x.split('_')[0]]
    <Do Processing for obtained 16K values>

这两种方法都非常缓慢。谁能指导我如何以更快的方式做到这一点。

注意:请暂时不要考虑平台,如果需要,我可以在 EC2 实例上运行脚本,但仍然需要解决上述问题。

【问题讨论】:

  • 我没有进行任何类型的分析,但这里有一些其他方法可以获取两个列表的交集geeksforgeeks.org/python-intersection-two-lists
  • 是组成这些列表的值已经在数据库中的某个地方。例如。您能否使用子选择在查询中提取这些值并在数据库本身中进行匹配/过滤。在 DB 中做这类事情几乎总是比在 Python 中更快。
  • @AnthonyOteri:好的,我想我可以尝试一下,谢谢。但是如果这也不起作用(由于业务逻辑限制)。上述问题还有其他解决方案/方法吗?
  • 您确定这是 Lambda 限制吗?这听起来像一个数据库限制。您是否考虑过将更合适的数据处理工具连接到您的数据库?
  • @RenatoByrro,是的,因为我收到错误消息:{“error”:“body size is too long”}。根据给定的链接,它提到它的 lambda 限制 - stackoverflow.com/questions/46298060/aws-lambda-response-error/…

标签: python python-3.x aws-lambda


【解决方案1】:

根据@AnthonyOteri 的建议,我主要在数据库端进行处理,它工作得很好,而且时间也少了很多。

【讨论】:

    【解决方案2】:

    您似乎已经使用数据库解决了这个问题,但您也可以在 Python 中使用更合适的数据结构大大加快这个速度。

    基本上,您将 Col2 中的每个值与 Col1 中的每个值进行比较,以查看它们是否具有相同的第一个元素。相反,您可以将 Col1 中的元素按其第一个元素进行分组,将它们存储在字典中,然后从该字典中获取与 Col2 中值的第一个元素相对应的值。

    import collections
    col1_dict = collections.defaultdict(list)
    for item1 in col1_list:
        col1_dict[item1.split('_')[0]].append(item1)
    
    for i in range(0, len(col2_list), 16000):
        matched_list = [item for val_to_check in col2_list[i:i + 16000]
                             for item in col1_dict[val_to_check.split('_')[0]]]
        # more processing
    

    这会将复杂度从 O(#col1 x #col2) 降低到 O(#col1 + #col2)。 (列表理解仍然有两个 for 循环,但由于 Col1 中的每个项目都将位于一个“桶”中,因此内部循环的 组合 运行时间仅为 #Col1 迭代。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多