我将SPARQL查询作为异步请求发送到SPARQL端点,目前DBpedia使用dotNetRDF library。虽然更简单的查询通常有效,但更复杂的查询有时会导致超时。
我正在寻找一种处理超时的方法,方法是在事件发生时捕获它们。
我使用one of the asynchronous QueryWithResultSet
overloads的SparqlRemoteEndpoint
class发送查询。
如SparqlResultsCallback
所述,如果异步请求失败,state
对象将替换为AsyncError
instance。这确实表明存在超时,但似乎在发送请求后仅 10分钟。例如,当我的超时是30秒时,我想知道请求是否成功30秒后。 (35秒也可以,但你明白了。)
这是一个发送两个请求的示例应用程序,第一个请求非常简单并且可能在超时内成功(此处设置为120秒),而第二个请求相当复杂并且可能很容易在DBpedia上失败:< / p>
using System;
using System.Collections.Concurrent;
using VDS.RDF;
using VDS.RDF.Query;
public class TestTimeout
{
private static string FormatResults(SparqlResultSet results, object state)
{
var result = new System.Text.StringBuilder();
result.AppendLine(DateTime.Now.ToLongTimeString());
var asyncError = state as AsyncError;
if (asyncError != null) {
result.AppendLine(asyncError.State.ToString());
result.AppendLine(asyncError.Error.ToString());
} else {
result.AppendLine(state.ToString());
}
if (results == null) {
result.AppendLine("results == null");
} else {
result.AppendLine("results.Count == " + results.Count.ToString());
}
return result.ToString();
}
public static void Main(string[] args)
{
Console.WriteLine("Launched ...");
Console.WriteLine(DateTime.Now.ToLongTimeString());
var output = new BlockingCollection<string>();
var ep = new SparqlRemoteEndpoint(new Uri("http://dbpedia.org/sparql"));
ep.Timeout = 120;
Console.WriteLine("Server == " + ep.Uri.AbsoluteUri);
Console.WriteLine("HTTP Method == " + ep.HttpMode);
Console.WriteLine("Timeout == " + ep.Timeout.ToString());
string query = "SELECT DISTINCT ?a\n"
+ "WHERE {\n"
+ " ?a <http://www.w3.org/2000/01/rdf-schema#label> ?b.\n"
+ "}\n"
+ "LIMIT 10\n";
ep.QueryWithResultSet(query,
(results, state) => {
output.Add(FormatResults(results, state));
},
"Query 1");
query = "SELECT DISTINCT ?v5 ?v8\n"
+ "WHERE {\n"
+ " {\n"
+ " SELECT DISTINCT ?v5\n"
+ " WHERE {\n"
+ " ?v6 ?v5 ?v7.\n"
+ " FILTER(regex(str(?v5), \"[/#]c[^/#]*$\", \"i\")).\n"
+ " }\n"
+ " OFFSET 0\n"
+ " LIMIT 20\n"
+ " }.\n"
+ " OPTIONAL {\n"
+ " ?v5 <http://www.w3.org/2000/01/rdf-schema#label> ?v8.\n"
+ " FILTER(lang(?v8) = \"en\").\n"
+ " }.\n"
+ "}\n"
+ "ORDER BY str(?v5)\n";
ep.QueryWithResultSet(query,
(results, state) => {
output.Add(FormatResults(results, state));
},
"Query 2");
Console.WriteLine("Queries sent.");
Console.WriteLine(DateTime.Now.ToLongTimeString());
Console.WriteLine();
string result = output.Take();
Console.WriteLine(result);
result = output.Take();
Console.WriteLine(result);
Console.ReadLine();
}
}
当我运行它时,我可重复地获得如下输出:
13:13:23
Server == http://dbpedia.org/sparql
HTTP Method == GET
Timeout == 120
Queries sent.
13:13:25
13:13:25
Query 1
results.Count == 10
13:23:25
Query 2
VDS.RDF.Query.RdfQueryException: A HTTP error occurred while making an asynchron
ous query, see inner exception for details ---> System.Net.WebException: Der Rem
oteserver hat einen Fehler zurückgegeben: (504) Gatewaytimeout.
bei System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
bei VDS.RDF.Query.SparqlRemoteEndpoint.<>c__DisplayClass13.<QueryWithResultSe
t>b__11(IAsyncResult innerResult)
--- Ende der internen Ausnahmestapelüberwachung ---
results == null
显然,确切的时间会有所不同,但关键点在于,在发送请求后,基于第二个查询的错误消息大约 10分钟,接近2分钟设置暂停。
我在这里是否错误地使用了dotNetRDF,或者我是否有意自行运行额外的计时器以自行测量超时并自行做出反应,除非同时收到任何响应?
答案 0 :(得分:2)
不,你没有错误地使用dotNetRDF,而是出现了一个错误,即在异步运行查询时,端点上设置的超时不会受到尊重。这已归档为CORE-393
顺便说一句,即使修复了这个错误,你也不一定会在设置超时时获得硬超时。基本上,您为Timeout
实例的SparqlRemoteEndpoint
属性设置的值,该值用于设置.Net Timeout
的{{1}}属性。 HttpWebRequest.Timeout的文档说明如下:
获取或设置GetResponse的超时值(以毫秒为单位) 和GetRequestStream方法。
因此,您可以等到超时以建立与HttpWebRequest
查询的连接,然后再次超时以开始接收响应。一旦开始收到响应,超时将变得无关紧要,并且处理响应的代码不会对其进行遵守。
因此,如果你想要一个硬超时,你最好自己实现它,从长远来看,这可能是我们可以添加到dotNetRDF的东西,但这实现起来更复杂,只需修复关于超时的错误而没有得到HTTP的尊重请求。