Finding objects which contains at least one element from subset using RavenDB and LINQ

点点圈 提交于 2019-12-23 20:32:42

问题


I have simple type Question:

public class Question
{
    public Question(string id)
    {
        Id = id;
        Tags = new List<string>();
    }

    public string Id { get; private set; }
    public IList<string> Tags { get; set; }            
}

I have defined sample collection of such questions:

var q1 = new Question("q1") { Tags = new List<string>() {"a"} };
var q2 = new Question("q2") { Tags = new List<string>() {"b"} };
var q3 = new Question("q3") { Tags = new List<string>() {"a", "b", "c"} };
var q4 = new Question("q4") { Tags = new List<string>() {"a", "b"} };
var q5 = new Question("q5") { Tags = new List<string>() {"z"} };
var q6 = new Question("q6");
var questions = new List<Question>() {q1, q2, q3, q4, q5, q6};

Now I need to find all questions, which contains at least one tag, from given subset. Subset is defined below:

string[] tags = new[] {"a", "b"};

I expect q1, q2, q3 and q4 to be returned. The query which I use to get desired result is:

var questions = DocumentSession.Query<Question>().AsQueryable();
questions = GetQuestionsToContainingAtLeastOneTagFromSubset(questions, tags)
// some other query restrictions
var result = questions.ToList(); // (**)

The function which suppose to impose restrictions on my collection is following:

private IQueryable<Question> GetQuestionsToContainingAtLeastOneTagFromSubset(IQueryable<Question> questions, IEnumerable<string> tags)
{
    var result = new List<Question>();
    foreach (var tag in tags)
    {
        var currentTag = tag;
        var resultForTag = questions.Where(x => x.Tags.Any(xTag => xTag == currentTag));
        result = result.Concat(resultForTag).ToList();
     }
     return result.GroupBy(x => x.Id).Select(grp => grp.First()).AsQueryable();
}

I think this is highly inefficient. I'd like to avoid using .ToList() inside the provided function. As I understand this .ToList() expressions queries the RavenDB and returns me partial results (BTW: am I right ?). This is not efficient. I only want to impose restrictions in the provided function, and execute the query after all of the restrictions are imposed. The (**) place is good for me to sent the batch to RavenDB retrieve query result.

How to improve that ?


回答1:


You can query lucene to get the questions with tags that match yor tag aray array something like this:

string[] tags = new[] { "a", "b" };
string queryRange = "(" + string.Join(" OR ", tags) + ")";

var res = session.Advanced.LuceneQuery<Question>()
               .Where("Tags:" + queryRange).ToList();

Note that this queries the entire indexed questions, not a subset. But I think you can append - I GUESS - to the query string expression. See Lucene docs for more about these kind of queries: http://lucene.apache.org/core/old_versioned_docs/versions/3_0_0/queryparsersyntax.html




回答2:


Try this code:

 var q1 = new Question("q1") { Tags = new List<string>() {"aa", "bb"} };
 var q2 = new Question("q2") { Tags = new List<string>() {"aa"} };
 var q3 = new Question("q3") { Tags = new List<string>() {"aa", "bb", "cc"} };
 var q4 = new Question("q4");
 var questions = new List<Question>() {q1, q2, q3, q4};
 string[] tags = new[] { "bb", "cc" };

 var res = (from p in questions where 
           (from q in tags where p.Tags.Contains(q) == true select p).ToArray().Count() >= 1 
            select p).Distinct(); 
 //If you want more speed you can try to add .AsParallel() after .Distinct()


来源:https://stackoverflow.com/questions/10137547/finding-objects-which-contains-at-least-one-element-from-subset-using-ravendb-an

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!