SPARQL クエリを非同期リクエストとして SPARQL エンドポイントに送信しています。現在、DBpediaはdotNetRDF ライブラリを使用しています。通常、単純なクエリは機能しますが、より複雑なクエリではタイムアウトが発生することがあります。
発生したイベントをキャプチャしてタイムアウトを処理する方法を探しています。
classの非同期QueryWithResultSet
オーバーロードの1 つを使用して、クエリを送信しています。SparqlRemoteEndpoint
で説明したように、非同期リクエストが失敗した場合SparqlResultsCallback
、state
オブジェクトはAsyncError
インスタンスに置き換えられます。これはタイムアウトが発生したことを示していますが、リクエストが送信されてから10 分後にしか発生していないようです。たとえば、タイムアウトが 30 秒の場合、30 秒後にリクエストが成功したかどうかを知りたいです。(35 秒でも構いませんが、お分かりいただけると思います。)
以下は、2 つの要求を送信するサンプル アプリケーションです。最初の要求は非常に単純で、タイムアウト (ここでは 120 秒に設定) 内に成功する可能性が高く、2 番目の要求はかなり複雑で、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
明らかに正確な時間は異なりますが、重要な点は、2 番目のクエリに基づくエラー メッセージが、要求が送信されてから約10 分後に受信され、タイムアウトに設定された 2 分にはほど遠いことです。
ここで dotNetRDF を間違って使用していますか、それともタイムアウトを自分で測定し、その間に応答が受信されない限り、自分で反応するために追加のタイマーを実行する必要があるのは意図的ですか?