我正在将 SPARQL 查询作为异步请求发送到 SPARQL 端点,目前 DBpedia使用dotNetRDF library 。虽然简单的查询通常可以工作,但更复杂的查询有时会导致超时。
我正在寻找一种通过捕获发生时的某些事件来处理超时的方法。
我使用 one of the asynchronous QueryWithResultSet
overloads 发送查询SparqlRemoteEndpoint
class的.
如SparqlResultsCallback
所述,state
对象将被替换为 AsyncError
instance如果异步请求失败。这确实表明存在超时,但似乎仅在发送请求后 10 分钟发生超时。当我的超时时间例如是30秒时,我想知道30秒后请求是否成功。 (35 秒也可以,但你明白了。)
这是一个发送两个请求的示例应用程序,第一个请求非常简单,很可能在超时(此处设置为 120 秒)内成功,而第二个请求则相当复杂,在 DBpedia 上很容易失败:
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,或者我是否有意运行一个额外的计时器来自己测量超时并自行使用react,除非同时收到任何响应?
最佳答案
不,您没有错误地使用 dotNetRDF,而是似乎存在一个错误,即异步运行查询时,端点上设置的超时不会得到遵守。这已归档为 CORE-393
顺便说一句,即使修复了这个错误,您也不一定会在设置的超时时遇到硬超时。本质上是您为 SparqlRemoteEndpoint
实例的 Timeout
属性设置的值,该值用于设置 .Net 的
。 HttpWebRequest.Timeout 的文档声明如下:Timeout
属性HttpWebRequest
Gets or sets the time-out value in milliseconds for the GetResponse and GetRequestStream methods.
因此,您可以等待超时时间来建立与 POST
查询的连接,然后再次等待超时时间来开始接收响应。一旦您开始接收响应,超时就变得无关紧要,并且处理响应的代码不会考虑超时。
因此,如果您想要一个硬超时,您最好自己实现它,从长远来看,这可能是我们可以添加到 dotNetRDF 中的东西,但实现起来更复杂,只需修复有关 HTTP 未兑现的超时的错误请求。
关于异步请求超时通知,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20996232/