Raven DB는 배열 항목의 하위 집합을 필터링하고 가장 저렴한 필터 결과 항목을 정렬합니다.

로든 흄

다양한 속성을 필터링하는 부모 클래스가 있다고 가정합니다. 그 중 하나는 items 배열 인 속성입니다. 이제 항목 배열이 최소값 이상이고 최대 값 이하인 경우에만 부모 항목을 반환하고 싶다고 가정 해 보겠습니다. ... 괜찮습니다. 그런 다음 해당 항목의 필터링 된 결과 집합을 정렬하려면 어떻게해야합니까?

내가 달성하려는 것을 보여주기 위해 ac # 바이올린 예제를 만들었습니다. 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"를 인덱스가 아닌 것으로 사용할 수 없다는 것입니다. 그래서 내가 변환의 결과로 주문할 수 없다면? 나는 그것이 올바르게 주문하지 않는 것을 필터링하지만 이것이 작동하도록 할 수 없었다. 투영 또는 교차점을 사용하여 원하는 것을 달성하거나 순위를 매기거나 try 메서드를 줄이려면 다른 것이 있습니까?

나는 내가 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 필터에서 사용하는 것과 동일한 유모차를 전달하는 index 및 transform을 사용하여 where 필터 및 order by 절을 수행하십시오. 그러나 이것이 작동하는지 확실하지 않습니까? 더 중요한 것은 내가 플러그인에 정렬 dll을 가져 오는 방법을 잘 모르겠습니다. 즉, 클래스가 어떤 이름 공간에 들어가야하는지, 가져 오는 데 필요한 이름 공간이 무엇인지, 사용해야하는 어셈블리 이름이 무엇인지 등 https : //에 따르면 ravendb.net/docs/article-page/3.5/csharp/server/plugins/what-are-plugins dll을 드롭하면 raven이이 작업을 수행하지만 필요한 네임 스페이스를 찾을 수 없습니다. IndexEntriesToComparablesGenerator에 대한 참조?

내 물건을 테스트하기 위해 linqpad 5를 사용하는 메신저 ... 맞춤 주문을 사용하려면 클래스를 참조해야합니다.

팁이나 조언 또는 길드 방법 / 예시 환영

로든 흄

그래서 변환에서 필터링을 할 수 있다는 생각이 들지 않았습니다.

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

나는 레이븐의 사람들이 나를 도왔지만 다른 사람들에게 지식을 공유하기 때문에 이것을 인정할 수 없습니다.

이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.

침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제

에서 수정
0

몇 마디 만하겠습니다

0리뷰
로그인참여 후 검토

관련 기사

Related 관련 기사

뜨겁다태그

보관