0

さまざまなプロパティでフィルター処理する親クラスがあると仮定します。そのうちの 1 つは、 items の配列であるプロパティです。ここで、アイテムの配列が最小値を超え、最大値を下回っている場合にのみ親アイテムを返したいとします...それで問題ありません。次に、それらのアイテムのフィルター処理された結果セットを並べ替えたい場合はどうすればよいですか

何を達成しようとしているのかを示すために、ac# fiddle の例を作成しました: https://dotnetfiddle.net/mV4d28 (foo1 の配列には foo2 の項目よりも少ない項目がありますが、foo2 が最初に返されることに注意してください)

インデックスを使用してこれを行う必要があるため、クエリで使用されるフィルター基準に基づいて順序を計算できるインデックスが必要です。

Elasticsearch にはこれを処理する内部ヒット関数があり、mongo にはこれも処理するパイプラインがあるので、Raven にもこれを行う方法が必要だと確信していますか?

インデックスと乳母車での変換だけを使用してこれを達成できることを望んでいたので、試してみました:

私のインデックスと変換は次のようになります

public class familyTransfrom : AbstractTransformerCreationTask<ParentItem>
{
    public class Result : ParentItem{
        public double[] ChildItemValuesFiltered { get; set; }
    }
    public familyTransfrom(){
        TransformResults = parents => from parent in parents
        let filterMinValue = Convert.ToDouble(ParameterOrDefault("FilterMinValue", Convert.ToDouble(0)).Value<double>())
        let filterMaxValue = Convert.ToDouble(ParameterOrDefault("FilterMaxValue", Convert.ToDouble(9999)).Value<double>())
        select new Result{
            ParentItemId = parent.ParentItemId,
            ParentItemName = parent.ParentItemName,
            ParentItemValue = parent.ParentItemValue,
            //ChildItemValuesFiltered = parent.ChildItems.Where(p => p.ChildItemValues.Any(y => Convert.ToDouble(y) >= Convert.ToDouble(filterMinValue) && Convert.ToDouble(y) <= Convert.ToDouble(filterMaxValue))).SelectMany(t => t.ChildItemValues).ToArray<double>(),
            ChildItemValuesFiltered = parent.ChildItems.SelectMany(p => p.ChildItemValues.Where(y => Convert.ToDouble(y) >= Convert.ToDouble(filterMinValue) && Convert.ToDouble(y) <= Convert.ToDouble(filterMaxValue))).ToArray<double>(),
            ChildItems = Recurse(parent, x => x.ChildItems).Select(y => y).ToArray()    
        };
    }
}
public class familyIndex : AbstractIndexCreationTask<ParentItem>{
        public class Result : ParentItem {
                public double[] ChildItemValues { get; set; }
        }             
        public familyIndex(){
            Map = parents => from parent in parents
                select new Result{
                    ParentItemId = parent.ParentItemId,
                    ParentItemName = parent.ParentItemName,
                    ParentItemValue = parent.ParentItemValue,
                    ChildItemValues = parent.ChildItems.SelectMany(p => p.ChildItemValues.Select(y => y)).ToArray(),  
                    ChildItems = Recurse(parent, x => x.ChildItems).Select(y => y).ToArray()  
                };                                                                              
                Index("ParentItemId", FieldIndexing.Analyzed);
                Index("ParentItemName", FieldIndexing.Analyzed);
                Index("ParentItemValue", FieldIndexing.Analyzed);
        Index("ChildItemValues", FieldIndexing.Analyzed);
        Index("ChildItems", FieldIndexing.Analyzed);
             }
}

私のクエリは次のとおりです(これはライブレイヴンプレイグラウンドを使用しているため、使用したい箱から出してすぐに動作するはずです)

using (IDocumentStore store = new DocumentStore { Url = "http://live-test.ravendb.net/", DefaultDatabase = "altha" })
{
    store.Initialize(); 
    using (IDocumentSession session = store.OpenSession()) 
    {
        if(1 == 2){         
            //foreach (ParentItem element in data.OfType<ParentItem>()) {
            //  session.Store((ParentItem)element);
            //  session.SaveChanges();
            //}
            new familyIndex().Execute(store);
            new familyTransfrom().Execute(store);
        }else{
            double filterMinValue = 3.0;
            double filterMaxValue = 4.0;
            var results =  session
                .Advanced
                .DocumentQuery<familyIndex.Result,familyIndex>()
                .WhereBetweenOrEqual("ChildItemValues", filterMinValue, filterMaxValue)
                .SetResultTransformer<familyTransfrom, familyTransfrom.Result>()
                .SetTransformerParameters(new Dictionary<string, RavenJToken> {
                    { "FilterMinValue", filterMinValue },
                    { "FilterMaxValue", filterMaxValue } })
                .OrderBy("ChildItemValues")
                .OfType<ParentItem>().ToList(); 
                results.Dump();                         
    }}
}

私が見つけたのは、変換結果から「ChildItemValuesFiltered」をインデックスではないとして使用できないことでした。変換の結果で注文できない場合はどうなりますか?正しく順序付けされていないため、これを機能させることができませんでした。プロジェクション、インターセクション、ランク、または試行方法を減らすことを使用して、私が望むものを達成するための別の方法はありますか?

必要に応じてhttps://ravendb.net/docs/article-page/3.5/csharp/indexes/querying/sorting#custom-sortingを使用できると考えていました

次のようにします。

public class SortByNumberOfCharactersFromEnd : IndexEntriesToComparablesGenerator
{
    private readonly double filterMinValue;
    private readonly double filterMinValue;

    public SortByNumberOfCharactersFromEnd(IndexQuery indexQuery)
        : base(indexQuery)
    {
        filterMinValue = IndexQuery.TransformerParameters["FilterMinValue"].Value<double>();     // using transformer parameters to pass the length explicitly
        filterMaxValue = IndexQuery.TransformerParameters["FilterMaxValue"].Value<double>();
    }

    public override IComparable Generate(IndexReader reader, int doc)
    {
        var document = reader.Document(doc);
        double[] childItemValues = (double[])document.GetValues("ChildItemValuesFiltered").Select(double.Parse).ToArray();          // this field is stored in index
        return childItemValues.Where(x => x >= min && x <= max).Min();
    }
}

次に、WHERE フィルターで使用するのと同じプラムを渡すインデックスとトランスフォームを使用して、where フィルターと order by 句を実行します。しかし、これがうまくいくかどうかはわかりませんか?さらに重要なことに、ソート dll をプラグインに取り込む方法、つまり、クラスがどの名前空間に属すべきか、どの名前空間をインポートする必要があるか、どのアセンブリ名を使用する必要があるかなどがわからないravendb.net/docs/article-page/3.5/csharp/server/plugins/what-are-plugins dllをドロップするだけで、ravenはこれを実行しますが、必要な名前空間が見つからないようですIndexEntriesToComparablesGenerator のリファレンス?

私はlinqpad 5を使用して自分のものをテストしています...カスタムオーダーを使用するには、クラスを参照する必要があります

ヒントやアドバイス、またはギルドの方法/例を歓迎します

4

1 に答える 1

0

そのため、変換でフィルタリングを実行できるとは思いもしませんでした

TransformResults = parents => from parent in parents
        let filterMinValue = Convert.ToDouble(ParameterOrDefault("FilterMinValue", Convert.ToDouble(0)).Value<double>())
        let filterMaxValue = Convert.ToDouble(ParameterOrDefault("FilterMaxValue", Convert.ToDouble(9999)).Value<double>())
        select new {
            ParentItemId = parent.ParentItemId,
            ParentItemName = parent.ParentItemName,
            ParentItemValue = parent.ParentItemValue,
            //ChildItemValuesFiltered = parent.ChildItems.Where(p => p.ChildItemValues.Any(y => Convert.ToDouble(y) >= Convert.ToDouble(filterMinValue) && Convert.ToDouble(y) <= Convert.ToDouble(filterMaxValue))).SelectMany(t => t.ChildItemValues).ToArray<double>(),
            ChildItemValuesFiltered = parent.ChildItems.SelectMany(p => p.ChildItemValues.Where(y => Convert.ToDouble(y) >= Convert.ToDouble(filterMinValue) && Convert.ToDouble(y) <= Convert.ToDouble(filterMaxValue))).ToArray<double>(),
            ChildItems = Recurse(parent, x => x.ChildItems).Select(y => y).ToArray()    
        } into r
        where r.ChildItemValuesFiltered.Length > 0
        orderby r.ChildItemValuesFiltered.Min()
        select r;

これにより、私が望んでいたものが得られます。サンプルクエリは次のとおりです。

http://live-test.ravendb.net/databases/altha/indexes/familyIndex?start=0&pageSize=25&resultsTransformer=familyTransfrom&tp-FilterMinValue=3&tp-FilterMaxValue=4

レイヴンの人たちが私を助けてくれたので、これを信用することはできませんが、他の人のために知識を共有しています

于 2016-12-31T16:21:59.663 に答える