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; } } } }
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; } } } } }