1

RavenDBとLuceneQueryを使用したグループ化の動作に苦労しています。

IEnumerableはToArray()などを呼び出したときにのみ評価されるという印象を常に持っていました。

次のクエリは、わかりやすくするために2つの部分に分割されています。

TotalledBalanceListでToArray()が呼び出されるまで、クエリが評価されることは期待できません。グループ化は、すべてのデータにわたってサーバー上で行われることを期待しています。ただし、実際の結果は、.Take()で指定されたアイテムの数によって異なります。Take(1024)を使用しない場合、デフォルトの128アイテムの結果が返されます。

データセット全体でグループ化を実行できる必要があります。

using (var session = MvcApplication.RavenSession)
{
    var computedBalanceList =
        from c in session.Advanced.LuceneQuery<Journal, Ledger_ByDateAndDebitIdAndCreditIdAndValues>()
        .Where(parameters)
        .OrderBy(c => c.DateAsString).Take(1024)
        select new LedgerBalanceDto
        {
            Account = account,
            Name = queryName,
            Debits = c.DebitId == account.Id
                         ? c.DebitValue
                         : 0,
            Credits = (c.CreditId == account.Id)
                          ? c.CreditValue
                          : 0,
            Currency = (c.DebitId == account.Id) ? c.DebitCurrency : c.CreditCurrency,
            CurrencySymbol = (c.DebitId == account.Id) ? c.DebitCurrencySymbol : c.CreditCurrencySymbol,
        };

    var totalledBalanceList =
        from balance in computedBalanceList
        group new {balance.Debits, balance.Credits} by new {balance.Currency, balance.CurrencySymbol}
        into grouping
        select new LedgerBalanceDto
        {
            Account = account,
            Currency = grouping.Key.Currency,
            CurrencySymbol = grouping.Key.CurrencySymbol,
            Debits = grouping.Sum(c => c.Debits),
            Credits = grouping.Sum(c => c.Credits),
            Name = queryName
        };

    return totalledBalanceList;

そしてインデックス:

public class Ledger_ByDateAndDebitIdAndCreditIdAndValues:AbstractIndexCreationTask<Journal>
{
    public Ledger_ByDateAndDebitIdAndCreditIdAndValues()
    {
        Map = journals => from c in journals
                          select new {c.Date,c.DateAsString, c.DebitId, c.CreditId,c.DebitValue,c.CreditValue};

        Index(x=>x.Date,FieldIndexing.Analyzed);
        Index(x=>x.DateAsString,FieldIndexing.Analyzed);
        Index(x=>x.DebitId,FieldIndexing.Analyzed);
        Index(x=>x.CreditId,FieldIndexing.Analyzed);

        Index(x=>x.DebitValue,FieldIndexing.Analyzed);
        Index(x=>x.CreditValue,FieldIndexing.Analyzed);

        Sort(x=>x.DateAsString,SortOptions.String);
    }
}

また、グループ化がフィルターの「外側」で行われるようにクエリを書き直しましたが、まったく同じ結果が得られます。つまり、結果はTake()に依存します。

var totalledBalanceList = from balance in
    from c in query
        .Where(parameters)
        .OrderBy(c => c.DateAsString)
    select new LedgerBalanceDto
    {
        Account = account,
        Name = queryName,
        Debits = c.DebitId == account.Id
                     ? c.DebitValue
                     : 0,
        Credits = (c.CreditId == account.Id)
                      ? c.CreditValue
                      : 0,
        Currency = (c.DebitId == account.Id) ? c.DebitCurrency : c.CreditCurrency,
        CurrencySymbol = (c.DebitId == account.Id) ? c.DebitCurrencySymbol : c.CreditCurrencySymbol,
    }
    group new {balance.Debits, balance.Credits} by new {balance.Currency, balance.CurrencySymbol}
    into grouping
    select new LedgerBalanceDto
    {
        Account = account,
        Currency = grouping.Key.Currency,
        CurrencySymbol = grouping.Key.CurrencySymbol,
        Debits = grouping.Sum(c => c.Debits),
        Credits = grouping.Sum(c => c.Credits),
        Name = queryName
    };
return totalledBalanceList;

これについての考えは大歓迎です。

Journalクラスの一部:

public class Journal
{
    public string Id { get; set; }
    public string DebitId{get;set;}
    public string CreditId{get;set;}
    public decimal? ExchangeRate { get; set; }
    public decimal CreditValue {get;set;}
    public decimal DebitValue {get;set;}
    public string DebitCurrency {get;set;}
    public string CreditCurrency {get;set;}
    public decimal Nett
    {
        get { return _nett; }
        set
        {
            _nett = value;

            CreditValue = Math.Round(Nett, 2);
            DebitValue = Math.Round(Nett * (ExchangeRate ?? 1), 2);
        }
    }
   etc ...
}

サンプルデータIEnumerable <Journal>:

Id     DebitId       CreditId      Nett     ExchangeRate     DbCurr     CrCurr   DbVal    CrVal

1      Expense1      Bank          100      2.03             BRL        USD      203.00   100.00
2      Expense2      Bank          50       null             USD        USD      50.00     50.00
3      Bank          Client1       300      null             USD        USD      300.00   300.00
4      Stock         Bank          300      null             USD        USD      300.00   300.00

たとえば、銀行にクエリを実行するときに、DbValとCrValを合計して残高を計算できるようにしたいのですが、そのためには、(クエリに従って)どちらか一方をゼロにする必要があります。

4

1 に答える 1

0

ここではLINQクエリとLuceneクエリを混在させています。つまり、クライアントで評価されます。

これの多くをインデックスに移動し、session.Advanced.LuceneQueryではなくsession.Queryを使用してクエリを実行する必要があります。

于 2012-08-15T09:58:34.403 に答える