如何优化在另一个RDD中搜索RDD内容

时间:2019-06-23 10:42:49

标签: apache-spark pyspark

我有一个问题,需要在另一个RDD中搜索一个RDD的内容。

这个问题与Efficient string matching in Apache Spark不同,因为我正在寻找完全匹配的项目,并且不需要使用ML堆栈的开销。

我是火花的新手,我想知道这些方法中哪种更有效,或者是否还有其他方法。 我有一个类似以下示例的关键字文件(在生产中,它可能达到200行)

示例关键字文件

0.47uF 25V X7R 10% -TDK C2012X7R1E474K125AA
20pF-50V NPO/COG - AVX- 08055A200JAT2A

我还有另一个文件(用制表符分隔),需要从中查找匹配项(在生产中,我最多有80条 Million 行)

C2012X7R1E474K125AA Conn M12 Circular PIN 5 POS Screw ST Cable Mount 5 Terminal 1 Port

第一种方法 我定义了UDF并在每一行中遍历关键字

keywords = sc.textFile("keys")
part_description = sc.textFile("part_description")


def build_regex(keywords):
    res = '('
    for key in keywords:
        res += '(?<!\\\s)%s(?!\\\s)|' % re.escape(key)
    res = res[0:len(res) - 1] + ')'
    return r'%s' % res


def get_matching_string(line, regex):
    matches = re.findall(regex, line, re.IGNORECASE)
    matches = list(set(matches))
    return list(set(matches)) if matches else None


def find_matching_regex(line):
    result = list()
    for keyGroup in keys:
        matches = get_matching_string(line, keyGroup)
        if matches:
            result.append(str(keyGroup) + '~~' + str(matches) + '~~' + str(len(matches)))
    if len(result) > 0:
        return result


def split_row(list):
    try:
        return Row(list[0], list[1])
    except:
        return None


keys_rdd = keywords.map(lambda keywords: build_regex(keywords.replace(',', ' ').replace('-', ' ').split(' ')))
keys = keys_rdd.collect()

sc.broadcast(keys)

part_description = part_description.map(lambda item: item.split('\t'))
df = part_description.map(lambda list: split_row(list)).filter(lambda x: x).toDF(
    ["part_number", "description"])

find_regex = udf(lambda line: find_matching_regex(line), ArrayType(StringType()))

df = df.withColumn('matched', find_regex(df['part_number']))

df = df.filter(df.matched.isNotNull())

df.write.save(path=job_id, format='csv', mode='append', sep='\t')

第二种方法 我以为我可以做更多的并行处理(而不是像上面那样遍历所有键),所以我在键和线之间做了笛卡尔积,分解并分解了键,然后将每个键与part列进行了比较

df = part_description.cartesian(keywords)

    df = df.map(lambda tuple: (tuple[0].split('\t'), tuple[1])).map(
        lambda tuple: (tuple[0][0], tuple[0][1], tuple[1]))

    df = df.toDF(['part_number', 'description', 'keywords'])

    df = df.withColumn('single_keyword', explode(split(F.col("keywords"), "\s+"))).where('keywords != ""')

    df = df.withColumn('matched_part_number', (df['part_number'] == df['single_keyword']))

    df = df.filter(df['matched_part_number'] == F.lit(True))

    df.write.save(path='part_number_search', format='csv', mode='append', sep='\t')

这些是正确的方法吗?我有什么办法可以更快地处理这些数据?

1 个答案:

答案 0 :(得分:1)

这些都是有效的解决方案,我在不同的情况下都使用过。

通过使用广播方法传递的数据更少,向每个执行器仅发送200条额外的行,而不是将您的> 80m行文件的每一行复制200次,因此这可能最终为您带来更快的速度。

当查找中的记录数无法实现广播(远大于200行)时,我使用了笛卡尔方法。

在您的情况下,我会使用广播。