2015-04-19 4 views
0

Я пытаюсь выполнить полнотекстовый поиск с MongoDb 3. Этот запрос отлично работает для меня:Невозможно выполнить «текст» команду из C#

var q = new QueryDocument(BsonSerializer.Deserialize<BsonDocument>(string.Format("{{ $text: {{ $search: {0} }} }}", JsonConvert.ToString(query.Query))); 
return await context.Books.Find(q).ToListAsync(); 

Но теперь я хочу, чтобы сортировать результаты по релевантности используя поле textScore. Я пытаюсь использовать такой код:

public static async Task<IEnumerable<T>> Search<T>(this IMongoDatabase database, string search)  where T : class, new() 
     { 
      var textSearchCommand = new CommandDocument 
      { 
       { "text", typeof(T).Name }, 
       { "search", search } 
      }; 
      var commandResult = await database.RunCommandAsync<TextSearchQueryResult<T>>( textSearchCommand); 

      return commandResult.Ok ? commandResult.Results.OrderBy(t => t.Score).Select(t => t. Record) : null; 
     } 

class TextSearchQueryResult<T> : CommandResult 
{ 
    public TextSearchQueryResult(BsonDocument response) 
     : base(response) 
    { 
    } 

    public IEnumerable<TextSearchResult<T>> Results 
    { 
     get 
     { 
      var results = Response["results"].AsBsonArray.Select(row => row.AsBsonDocument); 
      var resultObjects = results.Select(item => item.AsBsonDocument); 

      return resultObjects.Select(row => BsonSerializer.Deserialize<TextSearchResult<T>>(row)); 
     } 
    } 
} 

public class TextSearchResult<T> 
{ 
    public T Record { get; set; } 
    public double Score { get; set; } 
} 

Запуск этой команды я получаю такую ​​ошибку:

Command text failed: no such command: text 

Другой подход, который я нашел:

return await context.Books 
        .Find(Builders<Book>.Filter.Text(query.Query)) 
        //.Project(Builders<Book>.Projection.Include(new StringFieldDefinition<Book>("textScore"))) 
        .Sort(Builders<Book>.Sort.MetaTextScore("textScore")) 
        .ToListAsync(); 

Но в этом случае я получаю такую ​​ошибку:

Can't canonicalize query: BadValue must have $meta projection for all $meta sort keys (code: 17287) 

ответ

0

Я нашел один возможный подход, используя aggregation.

var pipeline = new List<BsonDocument> 
{ 
    BsonSerializer.Deserialize<BsonDocument>("{ $match: { $text: { $search: " + JsonConvert.ToString(query.Query) + " } } }"), 
    BsonSerializer.Deserialize<BsonDocument>("{ $sort: { score: { $meta: \"textScore\" } } }") 
}; 

var result = await context.Books.AggregateAsync(new BsonDocumentStagePipelineDefinition<Book, Book>(pipeline)); 
return await result.ToListAsync(); 

Как я вижу, результат отличается от моего предыдущего подхода. И, похоже, близок к соответствующему результату.

Смежные вопросы