rdflib中的自定义SPARQL函数
将自定义SPARQL函数挂接到rdflib的好方法是什么 我一直在rdflib中寻找自定义函数的入口点。我没有找到专门的入口点,但发现rdflib.plugins.sparql.CUSTOM_EVALS可能是添加自定义函数的地方 到目前为止,我已经尝试使用下面的代码。我觉得它很脏。我正在调用一个隐藏函数_eval,我不确定所有参数是否正确。除了构成我代码基础的custom_eval.py示例代码之外,我几乎找不到其他关于custom_eval的代码或文档rdflib中的自定义SPARQL函数,sparql,rdflib,Sparql,Rdflib,将自定义SPARQL函数挂接到rdflib的好方法是什么 我一直在rdflib中寻找自定义函数的入口点。我没有找到专门的入口点,但发现rdflib.plugins.sparql.CUSTOM_EVALS可能是添加自定义函数的地方 到目前为止,我已经尝试使用下面的代码。我觉得它很脏。我正在调用一个隐藏函数_eval,我不确定所有参数是否正确。除了构成我代码基础的custom_eval.py示例代码之外,我几乎找不到其他关于custom_eval的代码或文档 import rdflib from r
import rdflib
from rdflib.plugins.sparql.evaluate import evalPart
from rdflib.plugins.sparql.sparql import SPARQLError
from rdflib.plugins.sparql.evalutils import _eval
from rdflib.namespace import Namespace
from rdflib.term import Literal
NAMESPACE = Namespace('//custom/')
LENGTH = rdflib.term.URIRef(NAMESPACE + 'length')
def customEval(ctx, part):
"""Evaluate custom function."""
if part.name == 'Extend':
cs = []
for c in evalPart(ctx, part.p):
if hasattr(part.expr, 'iri'):
# A function
argument = _eval(part.expr.expr[0], c.forget(ctx, _except=part.expr._vars))
if part.expr.iri == LENGTH:
e = Literal(len(argument))
else:
raise SPARQLError('Unhandled function {}'.format(part.expr.iri))
else:
e = _eval(part.expr, c.forget(ctx, _except=part._vars))
if isinstance(e, SPARQLError):
raise e
cs.append(c.merge({part.var: e}))
return cs
raise NotImplementedError()
QUERY = """
PREFIX custom: <%s>
SELECT ?s ?length WHERE {
BIND("Hello, World" AS ?s)
BIND(custom:length(?s) AS ?length)
}
""" % (NAMESPACE,)
rdflib.plugins.sparql.CUSTOM_EVALS['exampleEval'] = customEval
for row in rdflib.Graph().query(QUERY):
print(row)
首先,我要感谢您展示了如何实现一个新的SPARQL函数 其次,通过使用您的代码,我能够创建一个SPARQL函数,该函数使用Levenshtein距离计算两个字符串。它非常有见解,我希望与大家分享,因为它包含了其他文档,可以帮助其他开发人员创建自己的定制SPARQL函数
# Import needed to introduce new SPARQL function
import rdflib
from rdflib.plugins.sparql.evaluate import evalPart
from rdflib.plugins.sparql.sparql import SPARQLError
from rdflib.plugins.sparql.evalutils import _eval
from rdflib.namespace import Namespace
from rdflib.term import Literal
# Import for custom function calculation
from Levenshtein import distance as levenshtein_distance # python-Levenshtein==0.12.2
def SPARQL_levenshtein(ctx:object, part:object) -> object:
"""
The first two variables retrieved from a SPARQL-query are compared using the Levenshtein distance.
The distance value is then stored in Literal object and added to the query results.
Example:
Query:
PREFIX custom: //custom/ # Note: this part refereces to the custom function
SELECT ?label1 ?label2 ?levenshtein WHERE {
BIND("Hello" AS ?label1)
BIND("World" AS ?label2)
BIND(custom:levenshtein(?label1, ?label2) AS ?levenshtein)
}
Retrieve:
?label1 ?label2
Calculation:
levenshtein_distance(?label1, ?label2) = distance
Output:
Save distance in Literal object.
:param ctx: <class 'rdflib.plugins.sparql.sparql.QueryContext'>
:param part: <class 'rdflib.plugins.sparql.parserutils.CompValue'>
:return: <class 'rdflib.plugins.sparql.processor.SPARQLResult'>
"""
# This part holds basic implementation for adding new functions
if part.name == 'Extend':
cs = []
# Information is retrieved and stored and passed through a generator
for c in evalPart(ctx, part.p):
# Checks if the function holds an internationalized resource identifier
# This will check if any custom functions are added.
if hasattr(part.expr, 'iri'):
# From here the real calculations begin.
# First we get the variable arguments, for example ?label1 and ?label2
argument1 = str(_eval(part.expr.expr[0], c.forget(ctx, _except=part.expr._vars)))
argument2 = str(_eval(part.expr.expr[1], c.forget(ctx, _except=part.expr._vars)))
# Here it checks if it can find our levenshtein IRI (example: //custom/levenshtein)
# Please note that IRI and URI are almost the same.
# Earlier this has been defined with the following:
# namespace = Namespace('//custom/')
# levenshtein = rdflib.term.URIRef(namespace + 'levenshtein')
if part.expr.iri == levenshtein:
# After finding the correct path for the custom SPARQL function the evaluation can begin.
# Here the levenshtein distance is calculated using ?label1 and ?label2 and stored as an Literal object.
# This object is than stored as an output value of the SPARQL-query (example: ?levenshtein)
evaluation = Literal(levenshtein_distance(argument1, argument2))
# Standard error handling and return statements
else:
raise SPARQLError('Unhandled function {}'.format(part.expr.iri))
else:
evaluation = _eval(part.expr, c.forget(ctx, _except=part._vars))
if isinstance(evaluation, SPARQLError):
raise evaluation
cs.append(c.merge({part.var: evaluation}))
return cs
raise NotImplementedError()
namespace = Namespace('//custom/')
levenshtein = rdflib.term.URIRef(namespace + 'levenshtein')
query = """
PREFIX custom: <%s>
SELECT ?label1 ?label2 ?levenshtein WHERE {
BIND("Hello" AS ?label1)
BIND("World" AS ?label2)
BIND(custom:levenshtein(?label1, ?label2) AS ?levenshtein)
}
""" % (namespace,)
# Save custom function in custom evaluation dictionary.
rdflib.plugins.sparql.CUSTOM_EVALS['SPARQL_levenshtein'] = SPARQL_levenshtein
for row in rdflib.Graph().query(query):
print(row)
请注意,此SPARQL函数仅适用于其实现的端点。即使查询中的SPARQL语法正确,也不可能在用于数据库(如DBPedia)的SPARQL查询中应用该函数。DBPedia端点还不支持此自定义函数。作为额外说明,我想提到的是,在其他SPARQL中,自定义函数的定义似乎更简单,请参见,例如,似乎更简单并不重要,这可能是设计决定的,或者是后来添加到RDFLib中的。如果你的代码可以工作,为什么不继续你的项目呢:D但是也许,一些RDFLib专家知道更多。你试过问开发者吗?示例/custom_eval.py实现的情况如何?关于示例/custom_eval.py:我的示例实际上是从这个python文件开发出来的。我现在看到rdflib的GitHub页面上出现了提交和问题,与我的问题有关:我看到这是在2017年3月完成的,但仍然是一个pull请求。听起来不错。然后,您可以分叉项目并在分叉上应用pull请求。
class ClassName():
"""DOCSTRING"""
def __init__(self):
"""DOCSTRING"""
# Save custom function in custom evaluation dictionary.
rdflib.plugins.sparql.CUSTOM_EVALS['SPARQL_levenshtein'] = SPARQL_levenshtein