私は、400 万の会社名の干し草の山から 30,000 個の針を探すファジー文字列マッチング スクリプトを持っています。スクリプトは問題なく動作しますが、AWS h1.xlarge での並列処理による高速化の試みは、メモリが不足しているため失敗しました。
以前の質問に答えて説明したように、より多くのメモリを取得しようとするのではなく、ワークフローを最適化する方法を見つけたいと思います - 私はこれにかなり慣れていないので、十分な余地があるはずです. ところで、私はすでにキューを試しました(これも機能しましたが、同じMemoryError
.
コードの中で最も関連性が高いと思われるものを次に示します。ロジックが十分に明確になることを願っています-必要に応じてさらに情報を提供してください:
def getHayStack():
## loads a few million company names into id: name dict
return hayCompanies
def getNeedles(*args):
## loads subset of 30K companies into id: name dict (for allocation to workers)
return needleCompanies
def findNeedle(needle, haystack):
""" Identify best match and return results with score """
results = {}
for hayID, hayCompany in haystack.iteritems():
if not isnull(haystack[hayID]):
results[hayID] = levi.setratio(needle.split(' '),
hayCompany.split(' '))
scores = list(results.values())
resultIDs = list(results.keys())
needleID = resultIDs[scores.index(max(scores))]
return [needleID, haystack[needleID], max(scores)]
def runMatch(args):
""" Execute findNeedle and process results for poolWorker batch"""
batch, first = args
last = first + batch
hayCompanies = getHayStack()
needleCompanies = getTargets(first, last)
needles = defaultdict(list)
current = first
for needleID, needleCompany in needleCompanies.iteritems():
current += 1
needles[targetID] = findNeedle(needleCompany, hayCompanies)
## Then store results
if __name__ == '__main__':
pool = Pool(processes = numProcesses)
totalTargets = len(getTargets('all'))
targetsPerBatch = totalTargets / numProcesses
pool.map_async(runMatch,
itertools.izip(itertools.repeat(targetsPerBatch),
xrange(0,
totalTargets,
targetsPerBatch))).get(99999999)
pool.close()
pool.join()
質問は次のとおりだと思います: どうすればすべてのワーカーの干し草の山をロードしないようにできますか? たとえば、データを共有したり、はるかに大きな干し草の山を針ではなくワーカー間で分割するなどの別のアプローチを採用したりできますか? クラッタを回避または排除してメモリ使用量を改善するにはどうすればよいですか?