1

很抱歉这个冗长的查询,我决定添加整个测试,这样即使是新手也能更容易地帮助我完成整个大脑融化。

使用指令是:

using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using Raven.Client;
using Raven.Client.Embedded;
using Raven.Client.Indexes;

如果我太长,请留下反馈,但是如果我添加一个完整的测试可能会出什么问题?

[TestFixture]
public class ClicksByScoreAndCardTest
{
    private IDocumentStore _documentStore;

    [SetUp]
    public void SetUp()
    {
        _documentStore = new EmbeddableDocumentStore {RunInMemory = true}.Initialize();
        _documentStore.DatabaseCommands.DisableAllCaching();

        IndexCreation.CreateIndexes(typeof (ClicksBySearchAndProductCode).Assembly, _documentStore);
    }

    [TearDown]
    public void TearDown()
    {
        _documentStore.Dispose();
    }

    [Test]
    public void ShouldCountTotalLeadsMatchingPreference()
    {
        var userFirst = new User {Id = "users/134"};
        var userSecond = new User {Id = "users/135"};
        var searchFirst = new Search(userFirst)
                              {
                                  Id = "searches/24",
                                  VisitId = "visits/63"
                              };
        searchFirst.Result = new Result();
        searchFirst.Result.Rows = new List<Row>(
            new[]
                {
                    new Row {ProductCode = "CreditCards/123", Score = 6},
                    new Row {ProductCode = "CreditCards/124", Score = 4}
                });

        var searchSecond = new Search(userSecond)
                               {
                                   Id = "searches/25",
                                   VisitId = "visits/64"
                               };

        searchSecond.Result = new Result();
        searchSecond.Result.Rows = new List<Row>(
            new[]
                {
                    new Row {ProductCode = "CreditCards/122", Score = 9},
                    new Row {ProductCode = "CreditCards/124", Score = 4}
                });

        var searches = new List<Search>
                           {
                               searchFirst,
                               searchSecond
                           };

        var click = new Click
                        {
                            VisitId = "visits/64",
                            ProductCode = "CreditCards/122",
                            SearchId = "searches/25"
                        };

        using (var session = _documentStore.OpenSession())
        {
            foreach (var search in searches)
            {
                session.Store(search);
            }
            session.Store(click);
            session.SaveChanges();
        }

        IList<ClicksBySearchAndProductCode.MapReduceResult> clicksBySearchAndProductCode = null;
        using (var session = _documentStore.OpenSession())
        {
            clicksBySearchAndProductCode = session.Query<ClicksBySearchAndProductCode.MapReduceResult>(ClicksBySearchAndProductCode.INDEX_NAME)
                .Customize(x => x.WaitForNonStaleResults()).ToArray();
        }
        Assert.That(clicksBySearchAndProductCode.Count, Is.EqualTo(4));
        var mapReduce = clicksBySearchAndProductCode
            .First(x => x.SearchId.Equals("searches/25")
                        && x.ProductCode.Equals("CreditCards/122"));
        Assert.That(mapReduce.Clicks,
                Is.EqualTo(1));
    }
}

public class ClicksBySearchAndProductCode :
    AbstractMultiMapIndexCreationTask
        <ClicksBySearchAndProductCode.MapReduceResult>
{
    public const string INDEX_NAME = "ClicksBySearchAndProductCode";

    public override string IndexName
    {
        get { return INDEX_NAME; }
    }

    public class MapReduceResult
    {
        public string SearchId { get; set; }
        public string ProductCode { get; set; }
        public string Score { get; set; }
        public int Clicks { get; set; }
    }

    public ClicksBySearchAndProductCode()
    {
        AddMap<Search>(
            searches =>
            from search in searches
            from row in search.Result.Rows
            select new
            {
                SearchId = search.Id,
                ProductCode = row.ProductCode,
                Score = row.Score.ToString(),
                Clicks = 0
            });
        AddMap<Click>(
            clicks =>
            from click in clicks
            select new
            {
                SearchId = click.SearchId,
                ProductCode = click.ProductCode,
                Score = (string)null,
                Clicks = 1
            });
        Reduce =
            results =>
            from result in results
            group result by
                new { SearchId = result.SearchId, ProductCode = result.ProductCode }
                into g
                select
                    new
                    {
                        SearchId = g.Key.SearchId,
                        ProductCode = g.Key.ProductCode,
                        Score = g.First(x => x.Score != null).Score,
                        Clicks = g.Sum(x => x.Clicks)
                    };
    }
}
public class User
{
    public string Id { get; set; }
}

public class Search
{
    public string Id { get; set; }
    public string VisitId { get; set; }
    public User User { get; set; }

    private Result _result = new Result();

    public Result Result
    {
        get { return _result; }
        set { _result = value; }
    }

    public Search(User user)
    {
        User = user;
    }
}

public class Result
{
    private IList<Row> _rows = new List<Row>();

    public IList<Row> Rows
    {
        get { return _rows; }
        set { _rows = value; }
    }
}

public class Row
{
    public string ProductCode { get; set; }
    public int Score { get; set; }
}

public class Click
{
    public string VisitId { get; set; }
    public string SearchId { get; set; }
    public string ProductCode { get; set; }
}

我的问题是我希望 Count 在该特定测试中是一个,但它似乎没有在 Click 地图中添加 Clicks,结果是 0 次点击。我很困惑,我确信我的问题有一个非常简单的解决方案,但我就是找不到它..

..希望有一个周末的战士可以把我带到他的翅膀下。

4

1 回答 1

1

是的,对我来说,这是一次脑筋急转弯,但仍然如此。正确的 reduce 应该如下所示:

Reduce =
    results =>
    from result in results
    group result by
        new { SearchId = result.SearchId, ProductCode = result.ProductCode }
        into g
        select
            new
            {
                SearchId = g.Key.SearchId,
                ProductCode = g.Key.ProductCode,
                Score = g.Select(x=>x.Score).FirstOrDefault(),
                Clicks = g.Sum(x => x.Clicks)
            };

并非所有地图都将分数设置为非空值,因此我的原始版本存在以下问题:

Score = g.First(x => x.Score != null).Score

心理笔记,使用:

Score = g.Select(x=>x.Score).FirstOrDefault()

不要使用:

Score = g.First(x => x.Score != null).Score
于 2012-07-07T21:01:05.233 回答