2017-02-09 1 views
0

아키텍처를 변경하기 위해 몇 가지 테스트를하고 있습니다. MongoDB를 삭제하고 대신 ElasticSearch를 사용하려고합니다. 그러나 나는이 기술을 정말로 모른다. 드라이버로 NEST를 사용 중이며 mongo에서 사용했던 쿼리를 번역 할 수 없습니다.C# NEST Elastic 검색 쿼리 여러 조건

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 
} 

: 일부 후 여기에 탄성 쿼리입니다

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. 클라이언트는 스레드로부터 안전하며 캐시를 광범위하게 사용하므로 단일 인스턴스를 만들어 다시 사용하는 것이 좋습니다. 이렇게하지 않으면 캐시가 모든 요청에 ​​따라 다시 작성되어야 성능이 저하 될 수 있습니다.
  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 
      } 
      } 
     } 
     ] 
    } 
    } 
} 

마지막으로 한가지 : 당신의 몽고 쿼리에, 당신은 접두사 오름차순으로 정렬되어 있기 때문에, 당신은 또한 득점없이 지낼 수있는 쿼리에서 filter 절을 사용하여 Elasticsearch 쿼리에서 prefix 쿼리를 실행합니다.

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

문제가 있으면 알려주세요.