예제 #1
0
파일: Index.cs 프로젝트: jon-adams/ravendb
			public IEnumerable<IndexQueryResult> IntersectionQuery(CancellationToken token)
			{
				using (IndexStorage.EnsureInvariantCulture())
				{
					AssertQueryDoesNotContainFieldsThatAreNotIndexed(indexQuery, parent.viewGenerator);
					IndexSearcher indexSearcher;
					using (parent.GetSearcher(out indexSearcher))
					{
						var subQueries = indexQuery.Query.Split(new[] { Constants.IntersectSeparator }, StringSplitOptions.RemoveEmptyEntries);
						if (subQueries.Length <= 1)
							throw new InvalidOperationException("Invalid INTERSECT query, must have multiple intersect clauses.");

						//Not sure how to select the page size here??? The problem is that only docs in this search can be part 
						//of the final result because we're doing an intersection query (but we might exclude some of them)
						int pageSizeBestGuess = (indexQuery.Start + indexQuery.PageSize) * 2;
						int intersectMatches = 0, skippedResultsInCurrentLoop = 0;
						int previousBaseQueryMatches = 0, currentBaseQueryMatches = 0;

                        var firstSubLuceneQuery = GetLuceneQuery(subQueries[0], indexQuery);

						//Do the first sub-query in the normal way, so that sorting, filtering etc is accounted for
						var search = ExecuteQuery(indexSearcher, firstSubLuceneQuery, 0, pageSizeBestGuess, indexQuery);
						currentBaseQueryMatches = search.ScoreDocs.Length;
						var intersectionCollector = new IntersectionCollector(indexSearcher, search.ScoreDocs);

						do
						{
							token.ThrowIfCancellationRequested();
							if (skippedResultsInCurrentLoop > 0)
							{
								// We get here because out first attempt didn't get enough docs (after INTERSECTION was calculated)
								pageSizeBestGuess = pageSizeBestGuess * 2;

								search = ExecuteQuery(indexSearcher, firstSubLuceneQuery, 0, pageSizeBestGuess, indexQuery);
								previousBaseQueryMatches = currentBaseQueryMatches;
								currentBaseQueryMatches = search.ScoreDocs.Length;
								intersectionCollector = new IntersectionCollector(indexSearcher, search.ScoreDocs);
							}

							for (int i = 1; i < subQueries.Length; i++)
							{
								var luceneSubQuery = GetLuceneQuery(subQueries[i], indexQuery);
								indexSearcher.Search(luceneSubQuery, null, intersectionCollector);
							}

							var currentIntersectResults = intersectionCollector.DocumentsIdsForCount(subQueries.Length).ToList();
							intersectMatches = currentIntersectResults.Count;
							skippedResultsInCurrentLoop = pageSizeBestGuess - intersectMatches;
						} while (intersectMatches < indexQuery.PageSize && //stop if we've got enough results to satisfy the pageSize
								 currentBaseQueryMatches < search.TotalHits && //stop if increasing the page size wouldn't make any difference
								 previousBaseQueryMatches < currentBaseQueryMatches); //stop if increasing the page size didn't result in any more "base query" results

						var intersectResults = intersectionCollector.DocumentsIdsForCount(subQueries.Length).ToList();
						//It's hard to know what to do here, the TotalHits from the base search isn't really the TotalSize, 
						//because it's before the INTERSECTION has been applied, so only some of those results make it out.
						//Trying to give an accurate answer is going to be too costly, so we aren't going to try.
						indexQuery.TotalSize.Value = search.TotalHits;
						indexQuery.SkippedResults.Value = skippedResultsInCurrentLoop;

						//Using the final set of results in the intersectionCollector
						int returnedResults = 0;
						for (int i = indexQuery.Start; i < intersectResults.Count && (i - indexQuery.Start) < pageSizeBestGuess; i++)
						{
							Document document = indexSearcher.Doc(intersectResults[i].LuceneId);
							IndexQueryResult indexQueryResult = parent.RetrieveDocument(document, fieldsToFetch, search.ScoreDocs[i]);
							if (ShouldIncludeInResults(indexQueryResult) == false)
							{
								indexQuery.SkippedResults.Value++;
								skippedResultsInCurrentLoop++;
								continue;
							}
							returnedResults++;
							yield return indexQueryResult;
							if (returnedResults == indexQuery.PageSize)
								yield break;
						}
					}
				}
			}
예제 #2
0
            public IEnumerable <IndexQueryResult> IntersectionQuery()
            {
                using (IndexStorage.EnsureInvariantCulture())
                {
                    AssertQueryDoesNotContainFieldsThatAreNotIndexes();
                    IndexSearcher indexSearcher;
                    using (parent.GetSearcher(out indexSearcher))
                    {
                        var subQueries = indexQuery.Query.Split(new[] { Constants.IntersectSeperator }, StringSplitOptions.RemoveEmptyEntries);
                        if (subQueries.Length <= 1)
                        {
                            throw new InvalidOperationException("Invalid INTRESECT query, must have multiple intersect clauses.");
                        }

                        //Not sure how to select the page size here??? The problem is that only docs in this search can be part
                        //of the final result because we're doing an intersection query (but we might exclude some of them)
                        int pageSizeBestGuess = (indexQuery.Start + indexQuery.PageSize) * 2;
                        int intersectMatches = 0, skippedResultsInCurrentLoop = 0;
                        int previousBaseQueryMatches = 0, currentBaseQueryMatches = 0;

                        var firstSubLuceneQuery = ApplyIndexTriggers(GetLuceneQuery(subQueries[0], indexQuery.DefaultField));

                        //Do the first sub-query in the normal way, so that sorting, filtering etc is accounted for
                        var search = ExecuteQuery(indexSearcher, firstSubLuceneQuery, 0, pageSizeBestGuess, indexQuery);
                        currentBaseQueryMatches = search.ScoreDocs.Length;
                        var intersectionCollector = new IntersectionCollector(indexSearcher, search.ScoreDocs);

                        do
                        {
                            if (skippedResultsInCurrentLoop > 0)
                            {
                                // We get here because out first attempt didn't get enough docs (after INTERSECTION was calculated)
                                pageSizeBestGuess = pageSizeBestGuess * 2;

                                search = ExecuteQuery(indexSearcher, firstSubLuceneQuery, 0, pageSizeBestGuess, indexQuery);
                                previousBaseQueryMatches = currentBaseQueryMatches;
                                currentBaseQueryMatches  = search.ScoreDocs.Length;
                                intersectionCollector    = new IntersectionCollector(indexSearcher, search.ScoreDocs);
                            }

                            for (int i = 1; i < subQueries.Length; i++)
                            {
                                var luceneSubQuery = ApplyIndexTriggers(GetLuceneQuery(subQueries[i], indexQuery.DefaultField));
                                indexSearcher.Search(luceneSubQuery, null, intersectionCollector);
                            }

                            var currentIntersectResults = intersectionCollector.DocumentsIdsForCount(subQueries.Length).ToList();
                            intersectMatches            = currentIntersectResults.Count;
                            skippedResultsInCurrentLoop = pageSizeBestGuess - intersectMatches;
                        } while (intersectMatches < indexQuery.PageSize &&                         //stop if we've got enough results to satisfy the pageSize
                                 currentBaseQueryMatches < search.TotalHits &&                     //stop if increasing the page size wouldn't make any difference
                                 previousBaseQueryMatches < currentBaseQueryMatches);              //stop if increasing the page size didn't result in any more "base query" results

                        var intersectResults = intersectionCollector.DocumentsIdsForCount(subQueries.Length).ToList();
                        //It's hard to know what to do here, the TotalHits from the base search isn't really the TotalSize,
                        //because it's before the INTERSECTION has been applied, so only some of those results make it out.
                        //Trying to give an accurate answer is going to be too costly, so we aren't going to try.
                        indexQuery.TotalSize.Value      = search.TotalHits;
                        indexQuery.SkippedResults.Value = skippedResultsInCurrentLoop;

                        //Using the final set of results in the intersectionCollector
                        int returnedResults = 0;
                        for (int i = indexQuery.Start; i < intersectResults.Count && (i - indexQuery.Start) < pageSizeBestGuess; i++)
                        {
                            Document         document         = indexSearcher.Doc(intersectResults[i].LuceneId);
                            IndexQueryResult indexQueryResult = parent.RetrieveDocument(document, fieldsToFetch, search.ScoreDocs[i].score);
                            if (ShouldIncludeInResults(indexQueryResult) == false)
                            {
                                indexQuery.SkippedResults.Value++;
                                skippedResultsInCurrentLoop++;
                                continue;
                            }
                            returnedResults++;
                            yield return(indexQueryResult);

                            if (returnedResults == indexQuery.PageSize)
                            {
                                yield break;
                            }
                        }
                    }
                }
            }