Пример #1
0
        /// <summary>
        /// Validates the search criteria.
        /// </summary>
        /// <param name="criteria">The criteria.</param>
        /// <param name="cultureName">Name of the culture.</param>
        /// <param name="validationException">The validation exception.</param>
        /// <returns></returns>
        public bool ValidateSearchCriteria(SearchCriteriaCollection criteria, string cultureName, out Exception validationException)
        {
            validationException = null;

            if (criteria == null || criteria.Count == 0)
            {
                validationException = new SearchException(ComponentsText.ExceptionSearchNoSearchCriteria);
                return(false);
            }

            SearchCriteriaString criteriaProperty;

            foreach (ISearchCriteria sc in criteria)
            {
                criteriaProperty = sc as SearchCriteriaString;
                if (criteriaProperty != null)
                {
                    if (StringExpressionKind.RegularExpression == criteriaProperty.WhatKind)
                    {
                        validationException = new SearchException(String.Format(ComponentsText.ExceptionLuceneSearchKindNotSupported, criteriaProperty.WhatKind));
                        break;                          // yet a warning
                    }
                    if (StringExpressionKind.XPathExpression == criteriaProperty.WhatKind)
                    {
                        validationException = new SearchException(String.Format(ComponentsText.ExceptionLuceneSearchKindNotSupported, criteriaProperty.WhatKind));
                        return(false);                          // error
                    }
                }
            }

            try {
                if (null == BuildLuceneQuery(criteria, null, GetAnalyzer(cultureName)))
                {
                    validationException = new SearchException(ComponentsText.ExceptionSearchQueryBuilder);
                    return(false);
                }
            } catch (Exception ex) {
                validationException = new SearchException(String.Format(ComponentsText.ExceptionSearchQueryBuilderFatal, ex.Message), ex);
                return(false);
            }

            return(true);
        }
Пример #2
0
        private static Query BuildLuceneQuery(SearchCriteriaCollection criteria, INewsFeed[] scope, Analyzer analyzer)
        {
            BooleanQuery masterQuery = null;
            BooleanQuery bTerms      = new BooleanQuery();
            BooleanQuery bRanges     = new BooleanQuery();

            for (int i = 0; criteria != null && i < criteria.Count; i++)
            {
                ISearchCriteria sc = criteria[i];
                if (sc is SearchCriteriaString)
                {
                    SearchCriteriaString c = (SearchCriteriaString)sc;

                    if (string.IsNullOrEmpty(c.What))
                    {
                        continue;
                    }

                    if (c.Where == SearchStringElement.Undefined)
                    {
                        AddBooleanClauseShould(bTerms, QueryFromStringExpression(c, IndexDocument.ItemContent, analyzer));
                    }
                    else
                    {
                        if ((c.Where & SearchStringElement.Title) > 0)
                        {
                            AddBooleanClauseShould(bTerms, QueryFromStringExpression(c, Keyword.ItemTitle, analyzer));
                        }

                        if ((c.Where & SearchStringElement.Link) > 0)
                        {
                            AddBooleanClauseShould(bTerms, QueryFromStringExpression(c, Keyword.ItemLink, analyzer));
                        }

                        if ((c.Where & SearchStringElement.Content) > 0)
                        {
                            AddBooleanClauseShould(bTerms, QueryFromStringExpression(c, IndexDocument.ItemContent, analyzer));
                        }

                        if ((c.Where & SearchStringElement.Subject) > 0)
                        {
                            AddBooleanClauseShould(bTerms, QueryFromStringExpression(c, Keyword.ItemTopic, analyzer));
                        }

                        if ((c.Where & SearchStringElement.Author) > 0)
                        {
                            AddBooleanClauseShould(bTerms, QueryFromStringExpression(c, Keyword.ItemAuthor, analyzer));
                        }
                    }
                }
                else if (sc is SearchCriteriaAge)
                {
                    SearchCriteriaAge c = (SearchCriteriaAge)sc;
                    Term   left, right;
                    string pastDate       = "19900101",
                           pastDateTime   = "199001010001";
                    string futureDate     = DateTime.Now.AddYears(20).DateToInteger().ToString(NumberFormatInfo.InvariantInfo),
                           futureDateTime = DateTime.Now.AddYears(20).DateToInteger().ToString(NumberFormatInfo.InvariantInfo) + "0001";

                    if (c.WhatRelativeToToday.CompareTo(TimeSpan.Zero) == 0)
                    {
                        // compare date only:
                        //TODO: validate provided date(s) to be in the allowed ranges (pastDate, futureDate)!
                        switch (c.WhatKind)
                        {
                        case DateExpressionKind.Equal:
                            AddBooleanClauseMust(bRanges, new PrefixQuery(new Term(Keyword.ItemDate, c.WhatAsIntDateOnly.ToString(NumberFormatInfo.InvariantInfo))));                                      //itemDate == whatYearOnly;
                            break;

                        case DateExpressionKind.OlderThan:
                            left  = new Term(Keyword.ItemDate, pastDate);
                            right = new Term(Keyword.ItemDate, c.What.DateToInteger().ToString(NumberFormatInfo.InvariantInfo));
                            AddBooleanClauseMust(bRanges, new RangeQuery(left, right, true));                                     // return itemDate < whatYearOnly;
                            break;

                        case DateExpressionKind.NewerThan:
                            left  = new Term(Keyword.ItemDate, c.What.DateToInteger().ToString(NumberFormatInfo.InvariantInfo));
                            right = new Term(Keyword.ItemDate, futureDate);
                            AddBooleanClauseMust(bRanges, new RangeQuery(left, right, true));                                     // return itemDate > whatYearOnly;
                            break;

                        default:
                            break;
                        }
                    }
                    else
                    {
                        DateTime dt = DateTime.Now.ToUniversalTime().Subtract(c.WhatRelativeToToday);
                        switch (c.WhatKind)
                        {
                        case DateExpressionKind.OlderThan:
                            left  = new Term(Keyword.ItemDate, pastDateTime);
                            right = new Term(Keyword.ItemDate, DateTools.TimeToString(dt.Ticks, DateTools.Resolution.MINUTE));
                            AddBooleanClauseMust(bRanges, new RangeQuery(left, right, true));
                            break;

                        case DateExpressionKind.NewerThan:
                            left  = new Term(Keyword.ItemDate, DateTools.TimeToString(dt.Ticks, DateTools.Resolution.MINUTE));
                            right = new Term(Keyword.ItemDate, futureDateTime);
                            AddBooleanClauseMust(bRanges, new RangeQuery(left, right, true));
                            break;

                        default:
                            break;
                        }
                    }
                }
                else if (sc is SearchCriteriaDateRange)
                {
                    SearchCriteriaDateRange c = (SearchCriteriaDateRange)sc;

                    Term left  = new Term(Keyword.ItemDate, c.Bottom.DateToInteger().ToString(NumberFormatInfo.InvariantInfo));
                    Term right = new Term(Keyword.ItemDate, c.Top.DateToInteger().ToString(NumberFormatInfo.InvariantInfo));
                    AddBooleanClauseMust(bRanges, new RangeQuery(left, right, true));                     // return itemDate > whatYearOnly;
                }
            }

            // now we build: +(terms...) +ranges
            if (bTerms.GetClauses().Length > 0)
            {
                masterQuery = new BooleanQuery();
                AddBooleanClauseMust(masterQuery, bTerms);
            }

            if (bRanges.GetClauses().Length > 0)
            {
                if (masterQuery != null)
                {
                    AddBooleanClauseMust(masterQuery, bRanges);                     // AND
                }
                else
                {
                    masterQuery = bRanges;
                }
            }

            // +scope
            if (scope != null && scope.Length > 0 && masterQuery != null)
            {
                StringBuilder scopeQuery = new StringBuilder("(");
                for (int i = 0; i < scope.Length; i++)
                {
                    scopeQuery.Append(scope[i].id);
                    scopeQuery.Append(" ");
                }
                scopeQuery[scopeQuery.Length - 1] = ')';
                // AND
                AddBooleanClauseMust(masterQuery, QueryFromStringExpression(scopeQuery.ToString(), IndexDocument.FeedID, analyzer));
            }

            return(masterQuery);
        }
Пример #3
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)));
        }