自我左边加入RavenDB

时间:2013-09-21 17:09:02

标签: c# linq nosql ravendb

RavenDB 中,我有一组针对不同10种或更多语言的网页PageTextElement。翻译者应该能够看到基本语言,如英语,将其与其他语言进行比较,例如瑞典语,这样他就可以轻松更新文本或插入翻译(如果缺少) 。对我来说,它听起来像是一个简单的自我左连接。我现在明白RavenDB没有support join out of the box. You have to use a map reduce index。我想我几乎可以开始工作了。

我可以在RavenDB中表达自我左连接和组:

SELECT bt.Page,bt.Token,bt.Webtext AS baseText,COUNT(ct.Webtext) 
FROM dbo.PageTextElement_TB bt
LEFT JOIN dbo.PageTextElement_TB AS ct 
    ON bt.Page=ct.Page 
    AND bt.Token = ct.Token 
    AND ct.Language='sv' 
WHERE bt.Language='en'
GROUP BY bt.Page,bt.Token,bt.Webtext

我能做什么的结果

|Page       |Token              |baseText                                       |count
--------------------------------------------------------------------------------------
|home       |PriceModel         |Based on weight and oxygen consumption         |1
|home       |RebateModel        |Truly Unique talent can reduce price with 50%  |0
|home       |RulesOfBoarding    |Do not break line                              |1  
|home       |Welcome            |Welcome to Aniara                              |1

但我想在RavenDB中表达两个联合集合中的字段:

SELECT bt.Page,bt.Token,bt.Webtext AS baseText,ct.Webtext AS compareText 
FROM dbo.PageTextElement_TB bt
LEFT JOIN dbo.PageTextElement_TB AS ct 
    ON bt.Page=ct.Page 
    AND bt.Token = ct.Token 
    AND ct.Language='sv' 
WHERE bt.Language='en'

结果我想要表

|Page       |Token              |baseText                         |compareText
--------------------------------------------------------------------------------------
|home       |PriceModel         |Based on weight and oxygen consumption |Priset baseras på vikt och syreförbrukning
|home       |RebateModel        |Truly Unique talent can reduce price with 50%  |NULL
|home       |RulesOfBoarding    |Do not break line     |Träng dig ej i kön
|home       |Welcome            |Welcome to Aniara     |Välkommen till Aniara

这是我的地图缩减索引,几乎可以满足我的需求。

 public class LeftJoinPageTextTranslationsCount : AbstractMultiMapIndexCreationTask<ComparePageTextElementCount>
        {
            public LeftJoinPageTextTranslationsCount()
            {
                AddMap<PageTextElement>(baseElements => 
                    from baseElement in baseElements.Where(l => l.Language == "en")
                    select new { Page = baseElement.Page, Token = baseElement.Token, baseElement.Webtext,WebtextCompare=(string)null, Count = 0 });

                AddMap<PageTextElement>(compareElements => 
                    from compareElement in compareElements.Where(l => l.Language == "sv")
                    select new { Page = compareElement.Page, Token = compareElement.Token, Webtext = (string)null,WebtextCompare=compareElement.Webtext, Count = 1 }
                    );
                Reduce = results => from result in results
                                    group result by
                                        new{Page = result.Page,Token = result.Token}
                                        into g
                                        select new
                                        {
                                            Page = g.Select(x => x.Page).Where(x => x != null).First(),
                                            Token = g.Select(x => x.Token).Where(x => x != null).First(),
                                            Webtext = g.Select(x => x.Webtext).Where(x => x != null).First(),
                                            WebtextCompare=g.Select(x => x.Webtext).Where(x => x != null).Last(),
                                            Count = g.Sum( x => x.Count)
                                        };
                Index(x => x.Webtext, FieldIndexing.Analyzed);
            }
        }

地图缩减索引

的结果
{
  "Page": "home",
  "Token": "PriceModel",
  "Webtext": "Based on weight and oxygen consumption",
  "WebtextCompare": "Based on weight and oxygen consumption",
  "Count": "1"
}
{
  "Page": "home",
  "Token": "RebateModel",
  "Webtext": "Truly Unique talent can reduce price with 50% ",
  "WebtextCompare": "Truly Unique talent can reduce price with 50% ",
  "Count": "0"
}
{
  "Page": "home",
  "Token": "Welcome",
  "Webtext": "Welcome to Aniara",
  "WebtextCompare": "Welcome to Aniara",
  "Count": "1"
}
{
  "Page": "home",
  "Token": "RulesOfBoarding",
  "Webtext": "Do not break line",
  "WebtextCompare": "Do not break line",
  "Count": "1"
}

我的问题是

为什么英文文本会出现在瑞典文本的哪个位置?

不幸的是, WebtextCompare字段显示英文文本而不是瑞典文。 我的gist可以找到更丰富的代码: 或者我的LeftJoin experiment project at github:实际上我的地图中的Count减少上面的索引是没有必要的,我想要另一种语言的WebTextCompare字段(在这个例子中是瑞典语)。

我想要的地图缩小指数的结果

{
  "Page": "home",
  "Token": "PriceModel",
  "Webtext": "Based on weight and oxygen consumption",
  "WebtextCompare": "Priset baseras på vikt och syreförbrukning",
  "Count": "1"
}
{
  "Page": "home",
  "Token": "RebateModel",
  "Webtext": "Truly Unique talent can reduce price with 50% ",
  "WebtextCompare": NULL,
  "Count": "0"
}
{
  "Page": "home",
  "Token": "Welcome",
  "Webtext": "Welcome to Aniara",
  "WebtextCompare": "Välkommen till Aniara",
  "Count": "1"
}
{
  "Page": "home",
  "Token": "RulesOfBoarding",
  "Webtext": "Do not break line",
  "WebtextCompare": "Träng dig ej i kön",
  "Count": "1"
}

1 个答案:

答案 0 :(得分:2)

嗯,这里似乎有一些事情发生。

a)你遇到这么多麻烦的原因是:

Webtext = g.Select(x => x.Webtext).Where(x => x != null).First(),
WebtextCompare=g.Select(x => x.Webtext).Where(x => x != null).Last(),

注意第二行,那里有 Webtext 。而不是WebtextCompare。

此外,您不应在索引中使用First或Last,您应该使用FirstOrDefault或LastOrDefault。

以下是您想要的完整索引定义:

public class LeftJoinPageTextTranslationsCount : AbstractMultiMapIndexCreationTask<ComparePageTextElementCount>
{
    public LeftJoinPageTextTranslationsCount()
    {
        AddMap<PageTextElement>(baseElements =>
                                from baseElement in baseElements.Where(l => l.Language == "en")
                                select
                                    new
                                        {
                                            baseElement.Page,
                                            baseElement.Token,
                                            baseElement.Webtext,
                                            WebtextCompare = (string) null,
                                            Count = 0
                                        });

        AddMap<PageTextElement>(compareElements =>
                                from compareElement in compareElements.Where(l => l.Language == "sv")
                                select
                                    new
                                        {
                                            compareElement.Page,
                                            compareElement.Token,
                                            Webtext = (string) null,
                                            WebtextCompare = compareElement.Webtext,
                                            Count = 1
                                        }
            );
        Reduce = results => from result in results
                            group result by
                                new { result.Page, result.Token }
                                into g
                                select new
                                    {
                                        g.Key.Page,
                                        g.Key.Token,
                                        Webtext = g.Select(x => x.Webtext).FirstOrDefault(x => x != null),
                                        WebtextCompare = g.Select(x => x.WebtextCompare).FirstOrDefault(x => x != null),
                                        Count = g.Sum(x => x.Count)
                                    };
        Index(x => x.Webtext, FieldIndexing.Analyzed);
    }
}

这是输出:

Proper results

B)可以使用以下索引处理LeftJoinProject:

public class LeftJoinIndex : AbstractMultiMapIndexCreationTask<LeftJoinIndex.ReduceResult>
{
    public class ReduceResult
    {
        public string TeacherName;
        public string[] Students;
    }
    public LeftJoinIndex()
    {
        AddMap<Students>(studentsList =>
                        from list in studentsList
                        from student in list.List
                        select new
                            {
                                TeacherName = student.HomeRoomTeacher,
                                Students = new[] { student.Name }
                            }
            );

        AddMap<Teachers>(teacherLists =>
                        from list in teacherLists
                        from teacher in list.List
                        select new
                            {
                                TeacherName = teacher.Name,
                                Students = new string[0]
                            }
        );

        Reduce = results =>
                 from reduceResult in results
                 group reduceResult by reduceResult.TeacherName
                     into g
                     select new
                         {
                             TeacherName = g.Key,
                             Students = g.SelectMany(x => x.Students)
                         };
    }
}

其中给出了以下输出:

LeftJoinIndex output