2017-08-11 33 views
0

我正在嘗試編寫一個api方法,它使用構建在應用程序級別上的通用查詢並使用NEST接口將其發送到elasticsearch數據庫。如何將預先創建的查詢對象發送到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在彈性所示的示例數據庫。

我要發送的查詢是:

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

例程提供正確的數據,當我在查詢一個空派,但我希望它返回任何數據,當我在爲一個值發送查詢。

我錯過了什麼?

編輯:

我所試圖做的是創造一個查詢構造和發送到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; 
    } 

查詢是在另一個應用程序構造和被髮送到Web 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:

我修改了API程序來實現對通用查詢到低級別查詢:

 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; 
    } 

這日常工作與正確形成的查詢字符串通過Web發送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,您只能提供請求的查詢部分,即不能包含將提供給_search API端點的JSON對象的"sort"或任何其他頂級屬性。

我認爲你可能在這裏後,而不是使用低級客戶發送搜索請求,但仍然返回一個強類型的響應SearchResponse<T>將返回使用高級客戶端進行搜索請求。

低級客戶端通過.LowLevel屬性暴露在高級客戶端上;假設Object query未來將被序列通過JSON.Net如預期,你可以做

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

我不能得到這個代碼的任何變化與我發送到API接口上方的對象的工作。不過,我認爲這可能是我想要採取的方法。目前,我不需要使用我正在進行的搜索進行排序或篩選,但是我可能希望在未來創建一個全新的調用來使用這些搜索。鑑於上面的編輯,你能否建議修改你的答案?它不會在MVC應用程序調用中構造字符串並返回任何結果。它會產生一個錯誤。 –

+0

您使用的是哪個版本的NEST?你定位的是什麼版本的Elasticsearch? Elasticsearch在「不起作用」時返回的錯誤信息是什麼?序列化查詢的樣子是什麼(您可以使用Fiddler查看):兩個版本上的https://www.elastic.co/guide/en/elasticsearch/client/net-api/current/troubleshooting.html –

+0

5.x 。我遇到的一般錯誤是「所有碎片失敗」或類似的東西。我檢查了「根本原因」,並告訴我(在我發佈之前的評論之後),使用字段升序/降序存在索引問題。至於向低級界面發送一般查詢,我相信我已經解決了這個問題。我將在稍後發佈更新。 –

相關問題