在AWS Glue中使用NLTK



我正在努力获得一个脚本工作,想知道是否有人成功地做到了这一点。我使用胶水来执行一个spark脚本,我试图使用NLTK模块来分析一些文本。我已经能够通过将NLTK模块上传到s3并引用Glue附加python模块配置的位置来导入NLTK模块。但是,我使用的是word_tokenize方法,该方法需要在nltk_data目录中下载punkt库。

我按照这个(使用Boto3从S3下载一个文件夹)将punkt文件复制到Glue中的tmp目录。但是,如果我在交互式glue会话中查看tmp文件夹,我看不到这些文件。当我运行word_tokenize方法时,我得到一个错误,说在默认位置(/usr/nltk_data的变体)中找不到包。

我将把所需的文件移到s3中的nltk包中,并尝试重写nltk标记器以直接加载文件,而不是加载nltk_data位置。但是我想先检查一下这里是否有人能够让这个工作,因为这似乎相当普遍。

我对NLTK的经验有限,但我认为nltk.download()将把punkt放在正确的位置。

import nltk
print('nltk.__version__', nltk.__version__)
nltk.download('punkt')
from nltk import word_tokenize
print(word_tokenize('Glue is good, but it has some rough edges'))

从日志

nltk.__version__ 3.6.3
[nltk_data] Downloading package punkt to /home/spark/nltk_data...
[nltk_data] Unzipping tokenizers/punkt.zip.
['Glue', 'is', 'good', ',', 'but', 'it', 'has', 'some', 'rough', 'edges']

我想在这里跟进,以防其他人遇到这些问题,找不到有效的解决方案。

离开这个项目一段时间后,我终于回来了,能够得到一个工作的解决方案。最初,我将tmp位置添加到nltk_data路径,并在那里下载所需的软件包。但是,这行不通。

nltk.data.path.append("/tmp/nltk_data")
nltk.download("punkt", download_dir="/tmp/nltk_data")
nltk.download("averaged_perceptron_tagger", download_dir="/tmp/nltk_data")

最终,我认为问题是我从punkt中需要的文件在工作节点上不可用。使用addFile方法,我终于可以使用nltk数据了。

sc.addFile('/tmp/nltk_data/tokenizers/punkt/PY3/english.pickle')

我遇到的下一个问题是,我试图从. withcolumn()方法调用UDF函数来获取每行的名词。这里的问题是withcolumn要求传递一个列,但nltk只处理字符串值。

不工作:

df2 = df.select(['col1','col2','col3']).filter(df['col2'].isin(date_list)).withColumn('col4', find_nouns(col('col1'))

为了让nltk工作,我传入了完整的数据帧,并循环遍历每一行。使用collect获取该行的文本值,然后构建一个新的数据框架,并返回包含所有原始列和新的nltk列的数据框架。对我来说,这似乎是令人难以置信的低效,但如果没有它,我无法得到一个有效的解决方案。

df2 = find_nouns(df)
def find_nouns(df):
data = []
schema = StructType([...])
is_noun = lambda pos: pos[:2] == 'NN'
for i in range(df.count()):
row = df.collect()[i]
tokenized = nltk.word_tokenize(row[0])
data.append((row[0], row[1], row[2], [word for (word, pos) inn nltk.pos_tag(tokenized) if is_noun(pos)]))
df2 = spark.createDataFrame(data=data, schema=schema)
return df2

我相信有更好的解决方案,但我希望这能帮助一些人把他们的项目变成一个初步的工作解决方案。

最新更新