2017-02-09 19 views
0

私はアーキテクチャを変更するためにいくつかのテストを行っています。私たちはMongoDBを落とし、代わりにElasticSearchを使用したいと考えています。しかし、私は本当にこの技術を知っていません。ドライバとしてNESTを使用していて、mongoで使用していたクエリを翻訳できません。C#NEST Elastic Search Query複数の条件

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

問題は、私は弾性の私のクエリモンゴを翻訳することはできませんが...

それはpainfullだったが、ここでは、弾性クエリです

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

- >解決策:

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")); 

をしかし、これは(/スキップすることなく、非常に簡単である取る)このクエリを行うための最善の方法であれば、今私は自分自身を求めている:私はC#でクエリを実行する方法を発見苦労コーディング。私が新しくなったので、おそらくもっと最適化されたクエリがあります...

+0

クエリが何をしようとしているのかを説明することができれば、素晴らしいことになります。これは、ESクエリを定式化する際に役立ちます。 mongoDbに精通していない – pratikvasa

答えて

1

解決策はうまく見えますが、強調する価値のある点がいくつかあります。

  1. クライアントはスレッドセーフで、キャッシュを大量に使用するため、1つのインスタンスを作成して再利用することをお勧めします。これを行わないと、キャッシュがすべての要求に応じて再構築され、パフォーマンスが低下する必要があります。
  2. 照会は一致するか一致しないか、すなわち一致する文書をスコアリングする必要のない述語である文書を見つけるので、range照会はbool照会filter節にラップすることができます。これらの句は、roaring bitmapsを使用してElasticsearchによってキャッシュできます。

NESTもboolクエリを構築するためにそれらを組み合わせることに速記としてQueryContainer(ルートクエリタイプ)上の演算子をオーバーロード。そして、あなたは(それぞれ.Skip().Take()、とエイリアス).From().Size()を使用してページ付け、などの分野の唯一の部分集合を指定することができます(上記の提案で)

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を使用してください。より完全な例は

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

最後の一つです:)あなたのMongoのクエリで、あなたは接頭辞昇順でソートされているので、あなたも得点見送る可能性を構築しますクエリがElasticsearchクエリでprefixクエリを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)); 

問題が見つかった場合は教えてください。