Python 在pyspark中对RDD元素计算Xquery

Python 在pyspark中对RDD元素计算Xquery,python,xml,apache-spark,pyspark,Python,Xml,Apache Spark,Pyspark,我们正在尝试读取大量XML,并在pyspark中对它们运行Xquery,例如XML书籍。我们正在使用spark xml utils库 我们希望将包含xmls的目录提供给pyspark 对所有这些对象运行Xquery以获得结果 参考答案: xquery处理器的定义,其中xquery是xquery的字符串: proc=sc.\u jvm.com.elsevier.spark\u xml\u utils.xquery.XQueryProcessor.getInstance(xquery) 我们正在

我们正在尝试读取大量XML,并在pyspark中对它们运行Xquery,例如XML书籍。我们正在使用spark xml utils

  • 我们希望将包含xmls的目录提供给pyspark
  • 对所有这些对象运行Xquery以获得结果
参考答案:

xquery处理器的定义,其中xquery是xquery的字符串:

proc=sc.\u jvm.com.elsevier.spark\u xml\u utils.xquery.XQueryProcessor.getInstance(xquery)

我们正在使用以下命令读取目录中的文件:

sc.wholeTextFiles(“xmls/test_文件”)

这为我们提供了一个RDD,其中包含作为元组列表的所有文件:

[(Filename1,FileContentAsString),(Filename2,File2ContentAsString)]

如果我们在字符串(FileContentAsString)上运行,xquery将进行计算并给出结果

问题:

PicklingError: Could not serialize object: TypeError: can't pickle _thread.RLock objects
books_xquery = """for $x in /bookstore/book
where $x/price>30
return $x/title/data()"""

proc_books = sc._jvm.com.elsevier.spark_xml_utils.xquery.XQueryProcessor.getInstance(books_xquery)

books_xml = sc.wholeTextFiles("xmls/books.xml")
books_xml.map(lambda x: proc_books.evaluate(x[1])).collect()
# Error
# I can share the stacktrace if you guys want
如果我们尝试使用lambda函数在RDD上运行proc.evaluate(),它将失败

test_file = sc.wholeTextFiles("xmls/test_files")
test_file.map(lambda x: proc.evaluate(x[1])).collect()

# Should give us a list of xquery results 
错误:

PicklingError: Could not serialize object: TypeError: can't pickle _thread.RLock objects
books_xquery = """for $x in /bookstore/book
where $x/price>30
return $x/title/data()"""

proc_books = sc._jvm.com.elsevier.spark_xml_utils.xquery.XQueryProcessor.getInstance(books_xquery)

books_xml = sc.wholeTextFiles("xmls/books.xml")
books_xml.map(lambda x: proc_books.evaluate(x[1])).collect()
# Error
# I can share the stacktrace if you guys want
这些功能在某种程度上起作用,但与上述功能不同:

打印xquery应用于的内容

test_file.map(lambda x: x[1]).collect()

# Outputs the content. if x[0], gives us the list of filenames
返回内容中的字符长度

test_file.map(lambda x: len(x[1])).collect()
# Output: [15274, 13689, 13696]
参考书籍示例:

PicklingError: Could not serialize object: TypeError: can't pickle _thread.RLock objects
books_xquery = """for $x in /bookstore/book
where $x/price>30
return $x/title/data()"""

proc_books = sc._jvm.com.elsevier.spark_xml_utils.xquery.XQueryProcessor.getInstance(books_xquery)

books_xml = sc.wholeTextFiles("xmls/books.xml")
books_xml.map(lambda x: proc_books.evaluate(x[1])).collect()
# Error
# I can share the stacktrace if you guys want

不幸的是,不可能在Python代码的映射调用中直接调用Java/Scala库。给出了一个很好的解释,为什么没有简单的方法来做到这一点。简而言之,原因是Py4J网关(将Python调用“转换”到JVM世界所必需的)仅存在于驱动程序节点上,而您试图执行的映射调用则在执行器节点上运行

解决这个问题的一种方法是将XQuery函数包装在Scala UDF中(已解释),但仍然需要编写几行Scala代码

编辑:如果您能够从XQuery切换到XPath,一个可能更简单的选择是更改(XPath)库。是一个用Python编写的XML库,也是

代码

xmls=spark.sparkContext.wholeTextFiles(“xmls/test_文件”)
将xml.etree.ElementTree作为ET导入
xpathquery=“…您的查询…”
flatMap(lambda x:ET.fromstring(x[1]).findall(xpathquery))\
.map(lambda x:x.text)\
.foreach(打印)
将针对从目录
xmls/test\u文件加载的所有文档打印运行
xpathquery
的所有结果


首先,调用返回每个文档中所有匹配项的列表时使用。通过使用
flatMap
此列表被展平(每个文件的结果可能包含多个元素)。在第二个
map
调用中,元素被映射到它们的元素,以便获得可读的输出。

它真的适用于Xquery吗?例如,因为以下查询失败:
keyrerror:(“对于/reportrations/CoID/CoID中的$companyName,其中$companyName/@Type='companyName'返回$companyName/data()”,无)。KeyError:“@”
您完全正确。我的答案只适用于xpath查询,而不适用于xquery表达式。很抱歉我已经在文本中添加了这些信息,尽管它可能对您没有帮助。查看xquery表达式,也许可以将其转换为xpath(
/CoIDs/CoID[@type='CompanyName']
)。也有可用于Python的xquery库,但我不能在这里给出任何建议。