rdflib中的自定义SPARQL函数

rdflib中的自定义SPARQL函数,sparql,rdflib,Sparql,Rdflib,将自定义SPARQL函数挂接到rdflib的好方法是什么 我一直在rdflib中寻找自定义函数的入口点。我没有找到专门的入口点,但发现rdflib.plugins.sparql.CUSTOM_EVALS可能是添加自定义函数的地方 到目前为止,我已经尝试使用下面的代码。我觉得它很脏。我正在调用一个隐藏函数_eval,我不确定所有参数是否正确。除了构成我代码基础的custom_eval.py示例代码之外,我几乎找不到其他关于custom_eval的代码或文档 import rdflib from r

将自定义SPARQL函数挂接到rdflib的好方法是什么

我一直在rdflib中寻找自定义函数的入口点。我没有找到专门的入口点,但发现rdflib.plugins.sparql.CUSTOM_EVALS可能是添加自定义函数的地方

到目前为止,我已经尝试使用下面的代码。我觉得它很脏。我正在调用一个隐藏函数_eval,我不确定所有参数是否正确。除了构成我代码基础的custom_eval.py示例代码之外,我几乎找不到其他关于custom_eval的代码或文档

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