2017-02-09 64 views
0

我正在做一些測試來改變我的架構。我們想要刪除MongoDB並改用ElasticSearch。但我真的不知道這項技術。我使用NEST作爲驅動程序,無法翻譯我曾經在mongo中使用的查詢。C#NEST彈性搜索查詢多個條件

public async Task<IEnumerable<Keyword>> GetKeywordsAsync(string prefix, int startIndex, int totalItems, int minimumTotalSearch, CancellationToken cancellationToken) 
    { 
     return await _mongoReader.GetEntitiesAsync<KeywordEntity, Keyword>(CollectionName, 
        queryable => 
         queryable.Where(entity => entity.KeywordName.StartsWith(prefix) && entity.TotalSearch >= minimumTotalSearch) 
           .OrderBy(entity => entity.KeywordName) 
           .Select(_keywordConverter.GetConverter()) 
           .Skip(startIndex) 
           .Take(totalItems), 
        cancellationToken).ConfigureAwait(false); 
    } 

public async Task<IEnumerable<TModel>> GetEntitiesAsync<TDocument, TModel>(string collectionName, 
      Func<IMongoQueryable<TDocument>, IMongoQueryable<TModel>> getQueryable, 
      CancellationToken cancellationToken) 
     { 
      var documents = GetDocuments<TDocument>(collectionName); 
      var query = getQueryable(documents.AsQueryable()); 
      return await query.ToListAsync(cancellationToken).ConfigureAwait(false); 
     } 

這裏是一個簡單的發現,我對ElasticSearch提出:

public async Task<IEnumerable<TModel>> FindAsync<TModel, TValue>(string index, 
     Expression<Func<TModel, TValue>> findExpression, TValue value, int limit, 
     CancellationToken cancellationToken) where TModel : class 
    { 
     var searchRequest = new SearchRequest<TModel>(index) 
     { 
      Query = 
       Query<TModel>.Match(
        a => a.Field(findExpression).Query(string.Format(CultureInfo.InvariantCulture, "{0}", value))), 
      Size = limit 
     }; 

     var resGet = await _elasticClientFactory.Create().SearchAsync<TModel>(searchRequest, cancellationToken).ConfigureAwait(false); 

     return resGet?.Documents; 
    } 

問題是我不能在彈性翻譯我的查詢蒙戈...

很不好受,但這裏是彈性查詢:

{ 
    "query": { 
    "bool": { 
     "must": [ 
     {"range" : { "totalSearch" : { "gte" : minimumTotalSearch }}}, 
     {"prefix": { "keywordName": prefix}} 
     ] 
    } 
    }, 
    "from": startIndex, 
    "size": totalItems 
} 

- >解決方案: 之後一些奮鬥編碼我找到了一種方法做查詢在C#:

var result = 
      ecf.Create() 
       .Search<KeywordEntity>(
        a => a.Query(
         z => 
          z.Bool(
           e => 
            e.Must(r => r.Range(t => t.Field(y => y.TotalSearch).GreaterThanOrEquals(minimumTotalSearch)), 
             t => t.Prefix(y => y.KeywordName, prefix)))).Index("keywords")); 

但現在我問自己,如果這是這樣做的查詢(不跳過/走哪是很容易)的最佳方式。因爲我是新的可能有更優化的查詢...

+0

如果你能解釋查詢試圖做什麼,那將是非常好的。這將有助於制定ES查詢。我不熟悉mongoDb – pratikvasa

回答

1

您的解決方案看起來不錯,但有幾點值得高亮顯示。

  1. 客戶端是線程安全的,並廣泛使用緩存,所以建議創建一個實例並重用它;不這樣做意味着緩存需要在每次請求時重建,從而降低性能。
  2. 由於range查詢查找到匹配或不匹配的文檔,即它是不需要對匹配文檔打分的謂詞,因此可以將range查詢打包在查詢filter子句的bool子句中;這些子句可以通過Elasticsearch使用roaring bitmaps進行緩存。

NEST也重載上QueryContainer(根查詢類型)運算符作爲簡寫到將它們組合起來,以建立一個bool查詢。您的溶液然後可以成爲(與上述建議)

var searchResponse = client.Search<KeywordEntity>(s => s 
    .Index("keywords") 
    .Query(q => q 
     .Prefix(p => p.KeywordName, prefix) && +q 
     .Range(r => r 
      .Field(y => y.TotalSearch) 
      .GreaterThanOrEquals(minimumTotalSearch) 
     ) 
    ) 
); 

可以使用.From().Size()(分別.Skip().Take(),化名)分頁,以及僅指定一個局部的字段集從源返回使用source filtering。更完整的例子是像

var client = new ElasticClient(); 

var minimumTotalSearch = 10; 
var prefix = "prefix"; 
var startIndex = 10; 
var totalItems = 10; 

var searchResponse = client.Search<KeywordEntity>(s => s 
    .Index("keywords") 
    .Query(q => q 
     .Prefix(p => p.KeywordName, prefix) && +q 
     .Range(r => r 
      .Field(y => y.TotalSearch) 
      .GreaterThanOrEquals(minimumTotalSearch) 
     ) 
    ) 
    // source filtering 
    .Source(sf => sf 
     .Includes(f => f 
      .Fields(
       ff => ff.KeywordName, 
       ff => ff.TotalSearch 
      ) 
     ) 
    ) 
    // sorting. By default, documents will be sorted by _score descending 
    .Sort(so => so 
     .Ascending(a => a.KeywordName) 
    ) 
    // skip x documents 
    .Skip(startIndex) 
    // take next y documents 
    .Take(totalItems) 
); 

此建立查詢

{ 
    "from": 10, 
    "size": 10, 
    "sort": [ 
    { 
     "keywordName": { 
     "order": "asc" 
     } 
    } 
    ], 
    "_source": { 
    "includes": [ 
     "keywordName", 
     "totalSearch" 
    ] 
    }, 
    "query": { 
    "bool": { 
     "must": [ 
     { 
      "prefix": { 
      "keywordName": { 
       "value": "prefix" 
      } 
      } 
     } 
     ], 
     "filter": [ 
     { 
      "range": { 
      "totalSearch": { 
       "gte": 10.0 
      } 
      } 
     } 
     ] 
    } 
    } 
} 

最後一兩件事:)由於您蒙戈查詢時,您是通過前綴升序排序,你也可以放棄得分prefix在Elasticsearch查詢中的查詢也通過bool查詢中的filter子句進行查詢。

0

查詢將是這樣的。

client.Search<KeywordEntity>(s => s.Index("<INDEX NAME>") 
            .Type("<TYPE NAME>") 
            .Query(q =>q 
             .Bool(b => b. 
              Must(prefix => prefix.Prefix(pre => pre.OnField("KeywordName").Value("PREFIX QUERY"))) 
              .Must(range => range.Range(ran => ran.OnField("TotalSearch").GreaterOrEquals(minimumTotalSearch))) 
         )).SortAscending("KeywordName") 
          .From(StartIndex) 
          .Size(totalItems)); 

讓我知道如果你發現任何困難。