/// <summary>
        /// Search for NewsItems, that match a provided criteria collection within a optional search scope.
        /// </summary>
        /// <param name="criteria">SearchCriteriaCollection containing the defined search criteria</param>
        /// <param name="scope">Search scope: an array of NewsFeed</param>
        /// <param name="tag">optional object to be used by the caller to identify this search</param>
        /// <param name="cultureName">Name of the culture.</param>
        /// <param name="returnFullItemText">if set to <c>true</c>, full item texts are returned instead of the summery.</param>
        public void SearchNewsItems(SearchCriteriaCollection criteria, INewsFeed[] scope, object tag, string cultureName,
                                    bool returnFullItemText)
        {
            // if scope is an empty array: search all, else search only in spec. feeds
            int feedmatches = 0;
            int itemmatches = 0;

            IList <INewsItem> unreturnedMatchItems = new List <INewsItem>();
            var fiList = new FeedInfoList(String.Empty);

            Exception ex;
            bool      valid = SearchHandler.ValidateSearchCriteria(criteria, cultureName, out ex);

            if (ex != null) // report always any error (warnings)
            {
                // render the error in-line (search result):
                fiList.Add(FeedSource.CreateHelpNewsItemFromException(ex).FeedDetails);
                feedmatches          = fiList.Count;
                unreturnedMatchItems = fiList.GetAllNewsItems();
                itemmatches          = unreturnedMatchItems.Count;
            }

            if (valid)
            {
                try
                {
                    // do the search (using lucene):
                    LuceneSearch.Result r = SearchHandler.ExecuteSearch(criteria, scope,
                                                                        this.Sources.Select(entry => entry.Source), cultureName);

                    // we iterate r.ItemsMatched to build a
                    // NewsItemIdentifier and ArrayList list with items, that
                    // match the read status (if this was a search criteria)
                    // then call FindNewsItems(NewsItemIdentifier[]) to get also
                    // the FeedInfoList.
                    // Raise ONE event, instead of two to return all (counters, lists)

                    SearchCriteriaProperty criteriaProperty = null;
                    foreach (ISearchCriteria sc in criteria)
                    {
                        criteriaProperty = sc as SearchCriteriaProperty;
                        if (criteriaProperty != null &&
                            PropertyExpressionKind.Unread == criteriaProperty.WhatKind)
                        {
                            break;
                        }
                    }


                    ItemReadState readState = ItemReadState.Ignore;
                    if (criteriaProperty != null)
                    {
                        readState = criteriaProperty.BeenRead ? ItemReadState.BeenRead : ItemReadState.Unread;
                    }


                    if (r != null && r.ItemMatchCount > 0)
                    {
                        /* append results */
                        var nids = new SearchHitNewsItem[r.ItemsMatched.Count];
                        r.ItemsMatched.CopyTo(nids, 0);

                        //look in every feed source to find source feed for matching news items
                        IEnumerable <FeedInfoList> results = Sources.Select(entry => entry.Source.FindNewsItems(nids, readState, returnFullItemText));
                        foreach (FeedInfoList fil in results)
                        {
                            fiList.AddRange(fil);
                        }

                        feedmatches          = fiList.Count;
                        unreturnedMatchItems = fiList.GetAllNewsItems();
                        itemmatches          = unreturnedMatchItems.Count;
                    }
                }
                catch (Exception searchEx)
                {
                    // render the error in-line (search result):
                    fiList.Add(FeedSource.CreateHelpNewsItemFromException(searchEx).FeedDetails);
                    feedmatches          = fiList.Count;
                    unreturnedMatchItems = fiList.GetAllNewsItems();
                    itemmatches          = unreturnedMatchItems.Count;
                }
            }

            RaiseSearchFinishedEvent(tag, fiList, unreturnedMatchItems, feedmatches, itemmatches);
        }
Exemple #2
0
        /// <summary>
        /// Executes a search.
        /// </summary>
        /// <param name="criteria">The criteria.</param>
        /// <param name="scope">The scope.</param>
        /// <param name="feedSources">The news handlers.</param>
        /// <param name="cultureName">Name of the culture.</param>
        /// <returns></returns>
        public Result ExecuteSearch(SearchCriteriaCollection criteria, INewsFeed[] scope, IEnumerable <FeedSource> feedSources, string cultureName)
        {
            if (!UseIndex)
            {
                return(null);
            }

            Query q = BuildLuceneQuery(criteria, scope, GetAnalyzer(cultureName));

            if (q == null)              // not validated
            {
                return(new Result(0, 0, GetList <SearchHitNewsItem> .Empty, GetArrayList.Empty));
            }

            //TODO: to be fixed -
            // next line causes issues with concurrent thread access to the search index:
            IndexSearcher searcher = new IndexSearcher(this._settings.GetIndexDirectory());
            Hits          hits     = null;

            while (hits == null)
            {
                try {
                    DateTime start = DateTime.Now;
                    hits = searcher.Search(q, Sort.RELEVANCE);
                    TimeSpan timeRequired = TimeSpan.FromTicks(DateTime.Now.Ticks - start.Ticks);
                    _log.Info(String.Format("Found {0} document(s) that matched query '{1}' (time required: {2})", hits.Length(), q, timeRequired));
                } catch (BooleanQuery.TooManyClauses) {
                    BooleanQuery.SetMaxClauseCount(BooleanQuery.GetMaxClauseCount() * 2);
                    _log.Info(String.Format("Search failed with error 'BooleanQuery.TooManyClauses'. Retry with BooleanQuery.MaxClauseCount == {0}", BooleanQuery.GetMaxClauseCount()));
                }
            }

            List <SearchHitNewsItem> items        = new List <SearchHitNewsItem>(hits.Length());
            HybridDictionary         matchedFeeds = new HybridDictionary();


            for (int i = 0; i < hits.Length(); i++)
            {
                Document doc = hits.Doc(i);

                INewsFeed f        = null;
                string    feedLink = doc.Get(Keyword.FeedLink);
                if (matchedFeeds.Contains(feedLink))
                {
                    f = (INewsFeed)matchedFeeds[feedLink];
                }

                if (f == null)
                {
                    foreach (FeedSource h in feedSources)
                    {
                        if (h.IsSubscribed(feedLink))
                        {
                            f = h.GetFeeds()[feedLink];
                            break;
                        }
                    }
                }

                if (f == null)
                {
                    continue;
                }
                SearchHitNewsItem item = new SearchHitNewsItem(f,
                                                               doc.Get(Keyword.ItemTitle),
                                                               doc.Get(Keyword.ItemLink),
                                                               doc.Get(IndexDocument.ItemSummary),
                                                               doc.Get(Keyword.ItemAuthor),
                                                               new DateTime(DateTools.StringToTime(doc.Get(Keyword.ItemDate))),
                                                               LuceneNewsItemSearch.NewsItemIDFromUID(doc.Get(IndexDocument.ItemID)));

                items.Add(item);
                if (!matchedFeeds.Contains(feedLink))
                {
                    matchedFeeds.Add(feedLink, f);
                }
            }


            return(new Result(items.Count, matchedFeeds.Count, items, new ArrayList(matchedFeeds.Values)));
        }