xMillion 条目的匿名化 - 需要性能提示

Posted

技术标签:

【中文标题】xMillion 条目的匿名化 - 需要性能提示【英文标题】:Anonymisation of xMillion entries - need performance hints 【发布时间】:2021-09-07 15:35:57 【问题描述】:

编辑:在每次调用时初始化名称数据集是一个巨大的错误(它将黑名单名称数据集加载到内存中)。 刚刚将 m = NameDataset() 移至主函数。没有测量,但它现在至少快 100 倍。


我使用dataTables 开发了一个(多语言)且可快速搜索的数据库。我想匿名化 mysql 数据库中的一些数据(名称等)。 在第一个例子中,我使用了 spaCy - 但因此字典没有经过训练 - 结果有太多误报。现在我对name-dataset 很满意。当然,它的工作方式完全不同,而且速度比 spaCy 慢得多,这得益于 GPU-Power。

因此自定义名称-DB 变得非常大(350.000 行)并且目标 DB 非常大 - 在循环中使用 regex.finditer 处理每个找到的单词需要永远(Ryzen 7 3700X) . 我们可以说 5 例/秒 - 这使得数百万行超过 100 小时。 因此每个进程只消耗大约 10% 的 CPU 功率,我启动了几个(最多 10 个)python 进程 - 最后它仍然需要很长时间。

我希望,我再也不必这样做了——但我害怕,我必须这样做。 所以我问,你有以下例程的性能提示吗?

main() 中的外部 for 循环 - 循环通过管道对象(DB 行)并调用 3 次(= 3 个项目/列)anonymize() 它也有一个 for 循环,贯穿每个找到的单词

重写它们,使用 CUDA/numba(可用 RTX 2070)等有意义吗? 还有其他性能提示吗?谢谢!

import simplejson as json
import sys, regex, logging, os
from names_dataset import NameDataset

def anonymize(sourceString, col):
    replacement = 'xxx'
    output = ''
    words = sourceString.split(' ')
    #and this second loop for each word (will run three times per row)
    for word in words:
        newword = word
        #regex for findind/splitting the words
        fRegExStr = r'(?=[^\s\r\n|\(|\)])(\w+)(?=[\.\?:,!\-/\s\(\)]|$)'
        pattern = regex.compile(fRegExStr)
        regx = pattern.finditer(word)
        if regx is None:
            if m.search_first_name(word, use_upper_Row=True):
                output += replacement
            elif m.search_last_name(word, use_upper_Row=True):
                output += replacement
            else:
                output += word
        else:
            for eachword in regx:
                if m.search_first_name(eachword.group(), use_upper_Row=True):
                    newword = newword.replace(eachword.group(), replacement)
                elif m.search_last_name(eachword.group(), use_upper_Row=True):
                    newword = newword.replace(eachword.group(), replacement)
            output += newword
        output += ' '
    return output

def main():
    #object with data is been piped to the python script, data structure:
    #MyRows: 
    #   [Text_A: 'some text', Text_B: 'some more text', Text_C: 'still text'],
    #   [Text_A: 'some text', Text_B: 'some more text', Text_C: 'still text'],
    #   ....several thousand rows
    #   
    MyRows = json.load(sys.stdin, 'utf-8')
    #this is the first outer loop for each row
    for Row in MyRows:
        xText_A = Row['Text_A']
        if Row['Text_A'] and len(Row['Text_A']) > 30:
            Row['Text_A'] = anonymize(xText_A, 'Text_A')
        xText_B = Row['Text_B']
        if xText_B and len(xText_B) > 10:
            Row['Text_B'] = anonymize(xText_B, 'Text_B')
        xMyRowText_C = Row['MyRowText_C']
        if xMyRowText_C and len(xMyRowText_C) > 10:
            Row['MyRowText_C'] = anonymize(xMyRowText_C, 'MyRowText_C')
    retVal = json.dumps(MyRows, 'utf-8')
    return retVal

if __name__ == '__main__':
    m = NameDataset() ## Right here is good - THIS WAS THE BOTTLENECK ##
    retVal = main()
    sys.stdout.write(str(retVal))

【问题讨论】:

如果不涉及数据库,请去掉标签[mysql] 【参考方案1】:

你在做

for word in words:
    newword = word
    #regex for findind/splitting the words
    fRegExStr = r'(?=[^\s\r\n|\(|\)])(\w+)(?=[\.\?:,!\-/\s\(\)]|$)'
    pattern = regex.compile(fRegExStr)
    regx = pattern.finditer(word)

意思是你regex.compile完全相同的事情在每个循环中,而你可以在循环开始之前做它并获得相同的结果。

我没有看到其他明显的优化,所以我建议profile 代码找出最耗时的部分。

【讨论】:

谢谢@Daweo。瓶颈在每次调用时都会初始化“m = NameDataset()”。将其移至 main() - 现在可以接受的速度很快。也感谢个人资料的提示!

以上是关于xMillion 条目的匿名化 - 需要性能提示的主要内容,如果未能解决你的问题,请参考以下文章

如何从 Firebase 匿名化 Analytics 中的 IP?

用sed和regex匿名化一些数据

Java匿名内部类和Lambda表达式

由浅入深掌握匿名类

数据科学:合成数据如何解决匿名化问题?

匿名实例化语法 - 好还是坏?