2017-08-11 10 views
0

アプリケーションレベルで構築された汎用クエリを取り、NESTインターフェイスを使用してelasticsearchデータベースに送信するAPIメソッドを作成しようとしています。事前作成されたQueryオブジェクトをNESTにどのように送信しますか?

私のルーチンのコードは、これまでのところ、次のとおりです。

[HttpPost] 
    [ActionName("Query")] 
    public IEnumerable<Account> Query([FromBody]Object query) 
    { 
     IEnumerable<Account> result = null; 
     var settings = new ConnectionSettings(
          baseAddress 
          ).DefaultIndex("bank").InferMappingFor<Account>(m => m.IndexName("bank").TypeName("account")); 
     var descriptor = new CreateIndexDescriptor("bank").Mappings(ms => ms.Map<Account>(m => m.AutoMap())); 
     var client = new ElasticClient(settings); 
     if (query == null) 
     { 
      var response = client.Search<Account>(s => s.Query(q => q.MatchAll()).Pretty().Size(1000)); 
      result = response.Documents; 
     } 
     else 
      { 
       var response = client.Search<Account>(s => s.Query(q => q.Raw(query.ToString()))); 
       result = response.Documents; 
      } 
     return result; 
    } 

私はhttps://www.elastic.co/guide/en/elasticsearch/reference/current/_exploring_your_data.htmlでの弾性に示すサンプル・データベースを使用しています。

私が送信するクエリは次のとおりです。私は、クエリにnullを送信するときに

{ 
    "query": { "match_all": {} }, 
    "sort": [ 
    { "account_number": "asc" } 
    ] 
} 

ルーチンは、権利データを配信するが、私はのための値で送信するとき、それはすべてのデータを返すようにしたいですクエリ。

私には何が欠けていますか?

EDIT:

私は、クエリを構築し、一般的なコールとを行うAPIとの完全なクエリとしてそれを処理するためのAPIコールに送られたAPIコール・インタフェースを作成されてやろうとしています汎用クエリオブジェクト(動作)

現在のコードは次のとおり

 public virtual IEnumerable<T> Query(Object query, String index) 
    { 
     IEnumerable<T> result = null; 
     var settings = new ConnectionSettings(baseAddress) 
          .DefaultIndex(index) 
          .InferMappingFor<T>(m => m.IndexName(index).TypeName(typeof(T).Name.ToLower())) 
          ; 
     var descriptor = new CreateIndexDescriptor(index).Mappings(ms => ms.Map<T>(m => m.AutoMap())); 
     var client = new ElasticClient(settings); 
     if (query == null) 
     { 
      var response = client.Search<T>(s => s.Query(q => q.MatchAll()).Pretty(true).Size(1000)); 
      if (response.IsValid) 
      { 
       result = response.Documents; 
      } 
      else 
      { 
       if (response.ServerError != null && response.ServerError.Error != null) 
        Logger.Logger.Warning(response.ServerError.Error.Reason); 
       else if (response.OriginalException != null) 
        Logger.Logger.Error(response.OriginalException); 
       else 
        Logger.Logger.Warning("NEST operation likely timed out."); 
      } 
     } 
     else 
     { 
      var type = client.Infer.TypeName(TypeName.From<T>()); 
      var response = client.Search<T>(s => s.Query(q => q.Raw(query.ToString())).Pretty(true).Size(1000)); 
      if (response.IsValid) 
      { 
       result = response.Documents; 
      } 
      else 
      { 
       if (response.ServerError != null && response.ServerError.Error != null) 
        Logger.Logger.Warning(response.ServerError.Error.Reason); 
       else if (response.OriginalException != null) 
        Logger.Logger.Error(response.OriginalException); 
       else 
        Logger.Logger.Warning("NEST operation likely timed out."); 
      } 
     } 
     client = null; 
     return result; 
    } 

クエリは、別のアプリケーションで構成され、ウェブAPI 2.xのサービスに送信されます。呼び出し元のコードは、現在、次のとおりです。

[HttpPost] 
    public ActionResult Search(String query) 
    { 
     var client1 = new ElasticClient(); 
     var matchQuery = new SimpleQueryStringQuery() 
     { 
      AllFields = true, 
      Analyzer = "standard", 
      Boost = 1.1, 
      Name = query, 
      Query = query, 
      DefaultOperator = Operator.Or, 
      AnalyzeWildcard = true, 
      Flags = SimpleQueryStringFlags.And | SimpleQueryStringFlags.Near | SimpleQueryStringFlags.Phrase, 

     }; 
     String sqsq = client1.Serializer.SerializeToString(matchQuery); 
     String queryString = String.Format("{{ \"simple_query_string\" : \r\n {0} \r\n}}", sqsq); 
     var repository = new ElasticRepository(); 
     var studies = repository.Query(queryString); 
     TempData["Studies"] = studies; 
     TempData["Query"] = query; 

     return RedirectToAction("Index"); 
    } 

は、私は何を探していますは、アプリケーションによって作成され、データベースと直接対話したWeb API 2.xの呼び出しを介して、それに送られたクエリを送信し、完全に汎用的なインタフェースです。

私は以下の答えで以下の答えを試してみました:elasticsearchデータベースは、作成されたクエリに問題があることを示します。単にクエリオブジェクトを送信して、すでに持っているNESTソリューションと同じレコードを返すことはありません。

低レベルのelasticsearch.NETがより適切なソリューションかもしれないと思われますが、私はそれを送信するようにクエリを生成することができませんでした。

私はこれに関する提案をしています。

UPDATE:ウェブを経由して送信され、適切に形成されたクエリ文字列と

 public virtual IEnumerable<T> Query(Object query, String index) 
    { 
     IEnumerable<T> result = null; 
     var type = typeof(T).Name.ToLower(); 
     var settings = new ConnectionSettings(baseAddress) 
          .DefaultIndex(index) 
          .InferMappingFor<T>(m => m.IndexName(index).TypeName(type)) 
          ; 
     var descriptor = new CreateIndexDescriptor(index).Mappings(ms => ms.Map<T>(m => m.AutoMap())); 
     var client = new ElasticClient(settings); 
     if (query == null) 
     { 
      var response = client.Search<T>(s => s.Query(q => q.MatchAll()).Pretty(true).Size(1000)); 
      if (response.IsValid) 
      { 
       result = response.Documents; 
      } 
      else 
      { 
       if (response.ServerError != null && response.ServerError.Error != null) 
        Logger.Logger.Warning(response.ServerError.Error.Reason); 
       else if (response.OriginalException != null) 
        Logger.Logger.Error(response.OriginalException); 
       else 
        Logger.Logger.Warning("NEST operation likely timed out."); 
      } 
     } 
     else 
     { 
      var response = client.LowLevel.Search<SearchResponse<T>>(index, type, query); 

      if (response.Success) 
      { 
       var body = response.Body; 
       if (body != null) 
       { 
        result = body.Documents; 
       } 
       else 
       { 
        if (response.ServerError != null && response.ServerError.Error != null) 
        { 
         Logger.Logger.Error(response.OriginalException); 
         Logger.Logger.Warning(response.ServerError.Error.Reason); 
         if (response.ServerError.Error.RootCause != null && response.ServerError.Error.RootCause.Count() > 0) 
         { 
          foreach (var cause in response.ServerError.Error.RootCause) 
          { 
           Logger.Logger.Warning(String.Format("Root cause {0}: {1}", cause.Index, cause.Reason)); 
          } 
         } 
        } 
        else if (response.OriginalException != null) 
         Logger.Logger.Error(response.OriginalException); 
        else 
         Logger.Logger.Warning("ElasticSearch operation likely timed out."); 
       } 
      } 
      else 
      { 
       if (response.ServerError != null && response.ServerError.Error != null) 
       { 
        Logger.Logger.Error(response.OriginalException); 
        Logger.Logger.Warning(response.ServerError.Error.Reason); 
        if (response.ServerError.Error.RootCause != null && response.ServerError.Error.RootCause.Count() > 0) 
        { 
         foreach (var cause in response.ServerError.Error.RootCause) 
         { 
          Logger.Logger.Warning(String.Format("Root cause {0}: {1}", cause.Index, cause.Reason)); 
         } 
        } 
       } 
       else if (response.OriginalException != null) 
        Logger.Logger.Error(response.OriginalException); 
       else 
        Logger.Logger.Warning("ElasticSearch operation likely timed out."); 
      } 
     } 
     client = null; 
     return result; 
    } 

このルーチン作品:私はへの一般的なクエリのための低レベルのクエリを実装するためのAPIルーチンを修正

Api 2.xコール。

次のようにWebアプリケーションレベルで形成し、Web APIに送信されたクエリ自体は次のとおりです。

[HttpPost] 
    public ActionResult Search(String query) 
    { 
     var client = new ElasticClient(); 
     var searchQuery = new 
     { 
      query = new 
      { 
       simple_query_string = new SimpleQueryStringQuery() 
       { 
        AllFields = true, 
        Analyzer = "standard", 
        Boost = 1.1, 
        Name = query, 
        Query = query, 
        DefaultOperator = Operator.Or, 
        AnalyzeWildcard = true, 
        Flags = SimpleQueryStringFlags.And | SimpleQueryStringFlags.Near | SimpleQueryStringFlags.Phrase, 
       } 
      }, 
      sort = new List<ISort>() { 
       new SortField() { 
        Field = Infer.Field("id"), 
        Order = SortOrder.Descending 
       } 
      } 

     }; 
     String sqsq = client.Serializer.SerializeToString(searchQuery); 
     var repository = new ElasticRepository(); 
     var studies = repository.Query(sqsq); 
     TempData["Studies"] = studies; 
     TempData["Query"] = query; 

     return RedirectToAction("Index"); 
    } 

ソート部は、次のエラーの原因となったため、このルーチンはまだ動作しません。

Root cause : Fielddata is disabled on text fields by default. Set fielddata=true on [id] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory. Alternatively use a keyword field instead.

これの治療法は、elasticsearchデータベースへの直接のコマンドでした。これは次のとおりです。

いずれの種類のフィールドでもソートを行うようにマッピングを変更する必要がありました。

検索クエリの書式設定では、オブジェクト初期化関数をより一般的なオブジェクト作成と組み合わせて、私が探していた抽象化の種類を提供します。

私が対処しようとしていた問題は解決したと思います。

答えて

0

"Raw" query in NEST使用して、あなただけの、すなわち、それは"sort"または_search APIエンドポイントに提供されることになるJSONオブジェクトの任意の他のトップレベルのプロパティを含めることはできません要求のクエリ部分を提供することができます。

低レベルのクライアントを使用して検索要求を送信することが考えられますが、依然として高いレベルのクライアントを使用して検索要求を行うときに返されるような強い型付き応答SearchResponse<T>が返されます。

下位レベルのクライアントは、.LowLevelプロパティを介して上位クライアントに公開されています。私は上記のAPIインタフェースに送るオブジェクトで動作するように、このコードのいずれかの変化を得ることができなかったJSON.Netによって予想通り入ってくるObject queryがシリアライズされると仮定すると、あなたは

void Main() 
{ 
    var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200")); 
    var connectionSettings = new ConnectionSettings(pool) 
     .InferMappingFor<Account>(m => m.IndexName("bank").TypeName("account")) 
     .DefaultIndex("default-index"); 

    var client = new ElasticClient(connectionSettings); 

    // query input to controller action 
    var query = new 
    { 
     query = new { match_all = new { } }, 
     sort = new [] { new { account_number = "asc" } } 
    }; 

    var index = client.Infer.IndexName(IndexName.From<Account>()); 
    var type = client.Infer.TypeName(TypeName.From<Account>()); 

    SearchResponse<Account> response = 
     client.LowLevel.Search<SearchResponse<Account>>(index, type, query).Body; 
} 

public class Account 
{ 
} 
+0

を行うことができます。しかし、これはおそらく私が取るべきアプローチであると私は思う。現在、私が行っている検索では、注文やフィルタリングは必要ありませんが、まったく新しい呼び出しを作成せずに、今後それらを採用することができます。上記の編集を考慮して、あなたの答えに変更を提案できますか? MVCアプリケーション呼び出しで構築した文字列は取得せず、結果も返しません。代わりにエラーが生成されます。 –

+0

どのNESTのバージョンを使用していますか?どのバージョンのElasticsearchをターゲットにしていますか? 「動作しない」とElasticsearchから返されるエラーメッセージは何ですか?シリアライズされたクエリはどのように見えますか(これはFiddlerで見ることができます):https://www.elastic.co/guide/en/elasticsearch/client/net-api/current/troubleshooting.html –

+0

5.x両方のバージョン。私が得ていた一般的なエラーは、「すべての破片が失敗しました」またはそれに類するものでした。私は "根本的な原因"を確認し、それは私が(前のコメントを投稿した後)昇順/降順のためのフィールドを使用すると、インデックスの問題があったと私に言った。低レベルのインターフェイスに一般的なクエリを送信することについては、私はその問題に対処していると信じています。私は後で更新を掲載する予定です。 –

関連する問題