使用投影进行MongoDB文本搜索

时间:2015-08-29 15:03:30

标签: c# mongodb mongodb-.net-driver

将MongoDB与C#和驱动程序2.0一起使用,我正在尝试执行以下操作:

  • 文字搜索
  • 按文字搜索分数对匹配进行排序
  • 将BigClass投影到SmallClass

这是类的简化版本:

onCreateOptionMenu()

如果我进行文本搜索,则非常简单:

class BigClass
{
    [BsonIgnoreIfDefault]
    public ObjectId             _id                 { get; set; }
    public string               Guid                { get; set; }
    public string               Title               { get; set; }
    public DateTime             CreationTime        { get; set; }
    // lots of other stuff

    [BsonIgnoreIfNull]
    public double?              TextMatchScore      { get; set; }       // Temporary place for the text match score, for sorting
}

class SmallClass
{
    [BsonIgnoreIfDefault]
    public ObjectId             _id                 { get; set; }
    public string               Title               { get; set; }

    [BsonIgnoreIfNull]
    public double?              TextMatchScore      { get; set; }       // Temporary place for the text match score, for sorting
}


如果我想按文字搜索的分数进行排序,那就更麻烦了(并且记录很少):

var F = Builders<BigClass>.Filter.Text("text I am looking for");
var Result = MongoDriver.Find(F).ToListAsync().Result;

基本上它需要我在类中添加一个字段(TextMatchScore)来保存结果。


如果我想获取数据,而不进行排序并将其投影到SmallClass,则很简单:

var F = Builders<BigClass>.Filter.Text("text I am looking for");
var P = Builders<BigClass>.Projection.MetaTextScore("TextMatchScore");
var S = Builders<BigClass>.Sort.MetaTextScore("TextMatchScore");
var Result = MongoDriver.Find(F).Project<BigClass>.Sort(S).ToListAsync().Result;


现在,如果&#34;我想要所有&#34;,那就是问题出现的地方:

var F = Builders<BigClass>.Filter.Text("text I am looking for");
var P = Builders<BigClass>.Projection.Include(_ => _.id).Include(_ => _.Title);
var Result = MongoDriver.Find(F).Project<SmallClass>(P).ToListAsync().Result;

我得到一个例外:

var F = Builders<BigClass>.Filter.Text("text I am looking for");
var P = Builders<BigClass>.Projection.MetaTextScore("TextMatchScore").Include(_ => _.id).Include(_ => _.Title).Include(_ => _.TextMatchScore);
var S = Builders<BigClass>.Sort.MetaTextScore("TextMatchScore");
var Result = MongoDriver.Find(F).Project<SmallClass>.Sort(S).ToListAsync().Result;

正如预期的那样,错误没有在任何地方记录,因为Mongo人希望用户自我记录所有内容。

如果我将投影投向&#39; BigClass&#39;,则没有问题,代码会运行并填充正确的字段。

如果你用C#谷歌那个文字,你找到的帖子是我的,当我试图弄清楚文本搜索时,这也很难记录。

因此,当我们将投影,文本搜索和排序结合起来时,在任何地方似乎都没有任何示例,我只是无法让它工作。

有谁知道这个问题的原因?

2 个答案:

答案 0 :(得分:1)

这对我有用:

var client = new MongoClient();
var db = client.GetDatabase("test");
var col = db.GetCollection<BigClass>("big");
await db.DropCollectionAsync(col.CollectionNamespace.CollectionName);

await col.Indexes.CreateOneAsync(Builders<BigClass>.IndexKeys.Text(x => x.Title));

await col.InsertManyAsync(new[]
{
    new BigClass { Title = "One Jumped Over The Moon" },
    new BigClass { Title = "Two went Jumping Over The Sun" }
});


var filter = Builders<BigClass>.Filter.Text("Jump Over");
// don't need to Include(x => x.TextMatchScore) because it's already been included with MetaTextScore.
var projection = Builders<BigClass>.Projection.MetaTextScore("TextMatchScore").Include(x => x._id).Include(x => x.Title);
var sort = Builders<BigClass>.Sort.MetaTextScore("TextMatchScore");

var result = await col.Find(filter).Project<SmallClass>(projection).Sort(sort).ToListAsync();

我删除了TextMatchScore的包含。它仍然会回来,因为它包含在MetaTextScore中(&#34; TextMatchScore&#34;)。

文档正在进行中。我们首先处理主要用例,因为那些用户受到的影响最大。这个用例并不常见,也没有记录。我们当然接受拉取请求,包括代码和文档。另外,请随时在CSHARP项目下的jira.mongodb.org上提交文档票据。

答案 1 :(得分:0)

适用于 MongoDB.Driver 2.x 的解决方案如下。重要的是不要在投影中包含,因为它会删除默认的,(或记得添加适当的投影)

查询:

 {
   "find":"SoceCollection",
   "filter":{
      "$text":{
         "$search":"some text to search"
      }
   },
   "sort":{
      "TextScore":{
         "$meta":"textScore"
      }
   },
   "projection":{
      "TextScore":{
         "$meta":"textScore"
      },
      "_id":0,
      "CreatedDate":0
   },
   "limit":20,
   "collation":{
      "locale":"en",
      "strength":1
   } ...

代码

var sort = Builders<BigModel>.Sort.MetaTextScore(nameof(LightModel.TextScore));
            var projection = Builders<BigModel>.Projection
            .MetaTextScore(nameof(LightModel.TextScore))
                    .Exclude(x => x.Id)
                    .Exclude(x => x.CreatedDate); 

 

            return await Collection()
               .Find(filter, new FindOptions { Collation = new Collation("en", strength: CollationStrength.Primary) })
                .Project<LightModel>(projection)
                .Sort(sort)
                .Limit(20)
                .ToListAsync();