我想知道一种在Java代码中编写此SPARQL查询的简单方法:
select ?input
?string
(strlen(?match)/strlen(?string) as ?percent)
where {
values ?string { "London" "Londn" "London Fog" "Lando" "Land Ho!"
"concatenate" "catnap" "hat" "cat" "chat" "chart" "port" "part" }
values (?input ?pattern ?replacement) {
("cat" "^x[^cat]*([c]?)[^at]*([a]?)[^t]*([t]?).*$" "$1$2$3")
("Londn" "^x[^Londn]*([L]?)[^ondn]*([o]?)[^ndn]*([n]?)[^dn]*([d]?)[^n]*([n]?).*$" "$1$2$3$4$5")
}
bind( replace( concat('x',?string), ?pattern, ?replacement) as ?match )
}
order by ?pattern desc(?percent)
此代码包含在讨论To use iSPARQL to compare values using similarity measures中。 此代码的目的是查找与DBPedia上的给定单词类似的资源。 这个方法考虑到我事先知道字符串及其长度。我想知道如何在参数化方法中编写此查询,无论单词和长度如何,它都会返回给我相似性度量。
答案 0 :(得分:7)
更新: ARQ - Writing Property Functions现已成为标准Jena文档的一部分。
看起来您喜欢使用SPARQL的语法扩展来执行查询中更复杂的部分。例如:
SELECT ?input ?string ?percent WHERE
{
VALUES ?string { "London" "Londn" "London Fog" "Lando" "Land Ho!"
"concatenate" "catnap" "hat" "cat" "chat" "chart" "port" "part" }
VALUES ?input { "cat" "londn" }
?input <urn:ex:fn#matches> (?string ?percent) .
}
ORDER BY DESC(?percent)
在这个例子中,假设<urn:ex:fn#matches>
是一个属性函数,它将自动执行匹配操作并计算相似度。
Jena文档很好地解释了如何write a custom filter function, 但是(截至2014年8月7日)几乎没有解释如何实现自定义属性函数。
我将假设您可以将您的答案转换为java代码以计算字符串相似性,并专注于可以容纳代码的属性函数的实现。
实施属性功能
每个属性函数都与特定的Context
相关联。这允许您将函数的可用性限制为全局或与特定数据集关联。
假设您有PropertyFunctionFactory
的实现(稍后显示),您可以按如下方式注册该函数:
<强> 注册 强>
final PropertyFunctionRegistry reg = PropertyFunctionRegistry.chooseRegistry(ARQ.getContext());
reg.put("urn:ex:fn#matches", new MatchesPropertyFunctionFactory);
PropertyFunctionRegistry.set(ARQ.getContext(), reg);
全局和数据集特定注册之间的唯一区别是Context
对象的来源:
final Dataset ds = DatasetFactory.createMem();
final PropertyFunctionRegistry reg = PropertyFunctionRegistry.chooseRegistry(ds.getContext());
reg.put("urn:ex:fn#matches", new MatchesPropertyFunctionFactory);
PropertyFunctionRegistry.set(ds.getContext(), reg);
<强> MatchesPropertyFunctionFactory 强>
public class MatchesPropertyFunctionFactory implements PropertyFunctionFactory {
@Override
public PropertyFunction create(final String uri)
{
return new PFuncSimpleAndList()
{
@Override
public QueryIterator execEvaluated(final Binding parent, final Node subject, final Node predicate, final PropFuncArg object, final ExecutionContext execCxt)
{
/* TODO insert your stuff to perform testing. Note that you'll need
* to validate that things like subject/predicate/etc are bound
*/
final boolean nonzeroPercentMatch = true; // XXX example-specific kludge
final Double percent = 0.75; // XXX example-specific kludge
if( nonzeroPercentMatch ) {
final Binding binding =
BindingFactory.binding(parent,
Var.alloc(object.getArg(1)),
NodeFactory.createLiteral(percent.toString(), XSDDatatype.XSDdecimal));
return QueryIterSingleton.create(binding, execCtx);
}
else {
return QueryIterNullIterator.create(execCtx);
}
}
};
}
}
因为我们创建的属性函数将列表作为参数,所以我们使用PFuncSimpleAndList
作为抽象实现。除此之外,在这些属性函数中发生的大部分魔法都是创建Binding
s,QueryIterator
,并执行输入参数的验证。
验证/结算备注
这应该足以让你继续编写自己的属性函数,如果那是你想要存放字符串匹配逻辑的地方。
没有显示的内容是输入验证。在这个答案中,我假设subject
和第一个列表参数(object.getArg(0)
)绑定(Node.isConcrete()
),而第二个列表参数(object.getArg(1)
)不是( Node.isVariable()
)。如果你的方法没有以这种方式调用,事情就会爆发。强化方法(将许多if-else
块与条件检查放在一起)或支持替代用例(即:如果它是变量,查找object.getArg(0)
的值)留给读者(因为它&#39 ;在实施过程中,需要进行演示,易于测试和显而易见。