예제 #1
0
        public async Task <SearchBlogResult> SearchBlogAsync(SearchModel m, int pageNumber, int pageSize)
        {
            SearchBlogResult result = new SearchBlogResult {
                SearchModel = m
            };
            var predicate = PredicateBuilder.New <Blog>(true);

            if (!string.IsNullOrWhiteSpace(m.FavUser))
            {
                predicate = predicate.And(b => _db.Favorites.Where(f => f.Username == m.FavUser).Any(f => f.BlogID == b.BlogID));
            }
            // If searching by title, include isApproved == null
            if (!string.IsNullOrWhiteSpace(m.Title))
            {
                predicate = predicate.And(b => b.isApproved != false);
            }
            else
            {
                predicate = predicate.And(b => b.isApproved == true);
            }
            if (m.StartDate.HasValue)
            {
                predicate = predicate.And(b => b.BlogDate >= m.StartDate.Value);
            }
            if (m.EndDate.HasValue)
            {
                var enddate = new DateTime(m.EndDate.Value.Year, m.EndDate.Value.Month, m.EndDate.Value.Day, 23, 59, 59);
                predicate = predicate.And(b => b.BlogDate <= enddate);
            }
            if (!string.IsNullOrWhiteSpace(m.Author))
            {
                predicate = predicate.And(b => b.Author == m.Author);
            }
            List <int> flatCategories;

            if (m.CurrentCategory.HasValue)
            {
                flatCategories = _categoryUtil.GetCategoryWithSubcategories(m.CurrentCategory.Value);
                predicate      = predicate.And(b => flatCategories.Contains(b.CategoryID));
            }
            if (m.CategoryIds != null && m.CategoryIds.Count() > 0)
            {
                flatCategories = m.CategoryIds.Aggregate(new List <int>(), (l, id) => { l.AddRange(_categoryUtil.GetCategoryWithSubcategories(id)); return(l); });
                predicate      = predicate.And(b => flatCategories.Contains(b.CategoryID));
            }
            if (!string.IsNullOrWhiteSpace(m.Tags))
            {
                var tags = TagUtil.SplitTags(m.Tags);
                IQueryable <TagsInBlog> tagsInBlog;
                if (!m.TagsMatchAny)
                {
                    tagsInBlog = tags.Aggregate(_db.TagsInBlogs.AsExpandable(), (r, name) => r.Join(
                                                    _db.TagsInBlogs.Where(tt => tt.tag.TagName.ToLower().Contains(name.ToLower())),
                                                    rr => rr.BlogID, t => t.BlogID, (rr, t) => rr));
                }
                else
                {
                    tagsInBlog = tags.Aggregate(_db.TagsInBlogs.AsExpandable().Where(_ => false), (r, name) => r.Union(
                                                    _db.TagsInBlogs.AsExpandable().Where(tt => tt.tag.TagName.ToLower().Contains(name.ToLower()))).Distinct());
                }
                var tagResult = await tagsInBlog.Select(tib => new { blogid = tib.BlogID, tag = tib.tag }).Distinct().ToListAsync();

                if (!m.TagsMatchAny)
                {
                    result.TagsSearched = tagResult.Where(tib =>
                                                          tags.Any(name =>
                                                                   tib.tag.TagName.ToSingleByteCharacterString().ToLower().Contains(
                                                                       name.ToSingleByteCharacterString().ToLower())))
                                          .Select(tib => tib.tag).Distinct();
                }
                else
                {
                    result.TagsSearched = tagResult.Select(tib => tib.tag).Distinct();
                }
                var blogIds = tagResult.Select(tib => tib.blogid).Distinct();
                predicate = predicate.And(b => blogIds.Contains(b.BlogID));
            }
            if (!string.IsNullOrWhiteSpace(m.Title))
            {
                var keywords       = m.Title.Replace('(', ' ').Replace(')', ' ').Replace('"', ' ').Split(new char[0], StringSplitOptions.RemoveEmptyEntries);
                var search         = _db.ContainsSearchBlog(string.Join(m.TitleMatchAny ? " OR " : " AND ", keywords.Select(s => '"' + s + '"')));
                var TitlePredicate = PredicateBuilder.New <Blog>(true);
                if (!m.TitleMatchAny)
                {
                    TitlePredicate = TitlePredicate.And(keywords.Aggregate(PredicateBuilder.New <Blog>(true), (p, word) => p.And(b => b.BlogTitle.Contains(word))));
                }
                else
                {
                    TitlePredicate = TitlePredicate.And(keywords.Aggregate(PredicateBuilder.New <Blog>(false), (p, word) => p.Or(b => b.BlogTitle.Contains(word))));
                }
                TitlePredicate = TitlePredicate.Or(b => search.Count(r => r.BlogID == b.BlogID) > 0);
                predicate      = predicate.And(TitlePredicate);
            }
            if (m.Harmony.HasValue)
            {
                predicate = predicate.And(b => b.isHarmony == m.Harmony.Value);
            }
            result.Blogs = await BlogHelper.getSortedQuery(_db, _db.Blogs.AsExpandable().Where(predicate), m.Sort).ToPagedListAsync(pageNumber, pageSize);

            return(result);
        }
예제 #2
0
        public async Task <SearchBlogResult> SearchBlogAsync(SearchModel m, int pageNumber, int pageSize)
        {
            SearchBlogResult searchBlogResult = new SearchBlogResult {
                SearchModel = m
            };

            if (!IsValid())
            {
                // Fallback
                return(await _dbBlogSearch.SearchBlogAsync(m, pageNumber, pageSize));
            }
            double?minScore = null;

            QueryContainer query(QueryContainerDescriptor <BlogIndexed> q)
            {
                var queries = new List <QueryContainer>();

                if (!string.IsNullOrWhiteSpace(m.Title))
                {
                    queries.Add(q.Bool(b => b.MustNot(q.Term("isApproved", false))));
                }
                else
                {
                    queries.Add(q.Term("isApproved", true));
                }
                if (m.StartDate.HasValue)
                {
                    queries.Add(q.DateRange(dr => dr.Field(f => f.CreateDate).GreaterThanOrEquals(m.StartDate)));
                }
                if (m.EndDate.HasValue)
                {
                    var enddate = new DateTime(m.EndDate.Value.Year, m.EndDate.Value.Month, m.EndDate.Value.Day, 23, 59, 59);
                    queries.Add(q.DateRange(dr => dr.Field(f => f.CreateDate).LessThanOrEquals(enddate)));
                }
                if (!string.IsNullOrWhiteSpace(m.Author))
                {
                    queries.Add(q.Term("author", m.Author));
                }
                IEnumerable <int> flatCategories = null;

                if (m.CurrentCategory.HasValue)
                {
                    flatCategories = _categoryUtil.GetCategoryWithSubcategories(m.CurrentCategory.Value);
                }
                if (m.CategoryIds != null && m.CategoryIds.Count() > 0)
                {
                    var ids = m.CategoryIds.Aggregate(new List <int>(), (l, id) => { l.AddRange(_categoryUtil.GetCategoryWithSubcategories(id)); return(l); });
                    if (flatCategories != null)
                    {
                        flatCategories = flatCategories.Intersect(ids);
                    }
                    else
                    {
                        flatCategories = ids;
                    }
                }
                if (flatCategories != null && flatCategories.Count() > 0)
                {
                    queries.Add(q.Terms(ts => ts.Field("categoryId").Terms(flatCategories)));
                }
                if (!string.IsNullOrWhiteSpace(m.Tags))
                {
                    var tags       = TagUtil.SplitTags(m.Tags);
                    var tagQueries = tags.Select(t => q.Bool(b => b.Should(
                                                                 q.Match(mm => mm.Field("tags").Query(t).Operator(Operator.And)),
                                                                 q.Match(mm => mm.Field("tags.ngram_lc").Query(t).Operator(Operator.And))))).ToArray();
                    if (m.TagsMatchAny)
                    {
                        queries.Add(q.Bool(b => b.Should(tagQueries)));
                    }
                    else
                    {
                        queries.Add(q.Bool(b => b.Must(tagQueries)));
                    }
                }
                if (!string.IsNullOrWhiteSpace(m.Title))
                {
                    var titles = m.TitleMatchAny ? m.Title.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries) : new[] { m.Title };
                    var field  = m.Title.Length > 30 ? "title" : "title.ngram_lc";
                    queries.Add(q.Bool(b => b.Should(
                                           titles.Select(t => new QueryContainer(new MatchQuery
                    {
                        Field    = field,
                        Query    = t,
                        Operator = Operator.And
                    })).ToArray())));
                    minScore = 5;
                }
                if (!string.IsNullOrWhiteSpace(m.Query))
                {
                    queries.Add(q.MultiMatch(mm => mm.Query(m.Query).Operator(Operator.And).Fields(new[] { "tags", "title", "title.ngram_lc", "content" })));
                    minScore = 5;
                }
                if (m.Harmony == true)
                {
                    queries.Add(q.Term("isHarmony", true));
                }
                return(q.Bool(bs => bs.Must(queries.ToArray())));
            }

            SortDescriptor <BlogIndexed> selector(SortDescriptor <BlogIndexed> s)
            {
                switch (m.Sort)
                {
                case "Date":
                    return(s.Ascending(b => b.CreateDate));

                case "Date_desc":
                    return(s.Descending(b => b.CreateDate));

                case "Visit_desc":
                    return(s.Descending(q => q.BlogVisit));

                case "Visit":
                    return(s.Ascending(q => q.BlogVisit));

                case "Post":
                    return(s.Ascending(q => q.PostCount));

                case "Post_desc":
                    return(s.Descending(q => q.PostCount));

                case "Rate":
                    return(s.Ascending(q => q.Rating));

                case "Rate_desc":
                    return(s.Descending(q => q.Rating));

                case "Score":
                    return(s.Ascending(SortSpecialField.Score));

                case "Score_desc":
                    return(s.Descending(SortSpecialField.Score));

                // TODO: AddDate, AddDate_desc for search in favorite.
                case null:
                default:
                    if (string.IsNullOrWhiteSpace(m.Query))
                    {
                        return(s.Descending(b => b.CreateDate));
                    }
                    return(s.Descending(SortSpecialField.Score));
                }
            }

            var result = await _client.SearchAsync <BlogIndexed>(s => {
                s = s.Query(query)
                    .TrackTotalHits(true)
                    .MinScore(minScore)
                    .Size(pageSize)
                    .Skip((pageNumber - 1) * pageSize)
                    .Sort(selector);
                if (new[] { m.Tags, m.Title, m.Query }.Any(v => !string.IsNullOrWhiteSpace(v)))
                {
                    s = s.Aggregations(agg => agg
                                       .Terms("distinct_tags", tg => tg.Field("tags.kw").Size(10))
                                       .Terms("categories", tg => tg.Field(b => b.CategoryId).Size(_categoryUtil.GetCategoryList().Count)));
                }
                return(s);
            }, _httpContext.RequestAborted);

            if (result.IsValid)
            {
                searchBlogResult.Blogs = new X.PagedList.StaticPagedList <Blog>(result.Documents.Select(d => d.ToBlog()), pageNumber, pageSize, (int)result.Total);
                if (result.Aggregations.ContainsKey("distinct_tags"))
                {
                    var tags = result.Aggregations.Terms("distinct_tags").Buckets.Select(b => b.Key);
                    searchBlogResult.TagsSearched = await _db.Tags.Where(t => tags.Contains(t.TagName)).ToListAsync();
                }
                if (result.Aggregations.ContainsKey("categories"))
                {
                    var counts = result.Aggregations.Terms <int>("categories").Buckets.ToDictionary(k => k.Key, k => k.DocCount.GetValueOrDefault(0));
                    long CalculateTotalItems(Category c)
                    {
                        if (c == null)
                        {
                            return(0);
                        }
                        counts.TryGetValue(c.CategoryID, out long count);
                        if (c.SubCategories != null)
                        {
                            foreach (var subcat in c.SubCategories)
                            {
                                count += CalculateTotalItems(subcat);
                            }
                            counts[c.CategoryID] = count;
                        }
                        return(count);
                    }

                    long total = 0;
                    foreach (var main in _categoryUtil.GetCategoryList().Where(h => !h.ParentCategoryID.HasValue))
                    {
                        total += CalculateTotalItems(main);
                    }
                    counts[0] = total;
                    searchBlogResult.SearchModel.CategoryItemCount = counts.Where(v => v.Value > 0).ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
                }
            }
            else
            {
                _logger.LogError(result.DebugInformation);
                searchBlogResult.Blogs = new X.PagedList.PagedList <Blog>(Enumerable.Empty <Blog>(), pageNumber, pageSize);
            }
            return(searchBlogResult);
        }