Пример #1
0
        /// <summary>
        /// Performs a search using the specified <paramref name="sortOptions"/>.
        /// </summary>
        /// <param name="operation">The boolean operation the search should be based on.</param>
        /// <param name="sortOptions">The sort options specyfing how the results should be sorted.</param>
        /// <param name="results">The results of the search.</param>
        /// <param name="total">The total amount of results returned by the search.</param>
        protected virtual void Execute(IBooleanOperation operation, ISortOptions sortOptions, out IEnumerable <ISearchResult> results, out long total)
        {
            // Cast the boolean operation to IQueryExecutor
            IQueryExecutor executor = operation;

            // If "SortField" doesn't specified, we don't apply any sorting
            if (!string.IsNullOrWhiteSpace(sortOptions.SortField))
            {
                switch (sortOptions.SortOrder)
                {
                case SortOrder.Ascending:
                    executor = operation.OrderBy(new SortableField(sortOptions.SortField, sortOptions.SortType));
                    break;

                case SortOrder.Descending:
                    executor = operation.OrderByDescending(new SortableField(sortOptions.SortField, sortOptions.SortType));
                    break;

                default:
                    throw new Exception($"Unsupported sort order: {sortOptions.SortOrder}");
                }
            }

            if (sortOptions is IOffsetOptions offset)
            {
                ISearchResults allResults = executor.Execute();

                // Update the total amount of results
                total = allResults.TotalItemCount;

                // Apply limit and offset
                results = allResults
                          .Skip(offset.Offset)
                          .Take(offset.Limit);
            }
            else
            {
                // Since no offset or limit is specified, we request all results
                ISearchResults allResults = executor.Execute(int.MaxValue);

                // Update the total amount of results
                total = allResults.TotalItemCount;

                // Update "results" with the value of "allResults" as we're not filtering the results
                results = allResults;
            }
        }
        private IEnumerable <ISearchResult> PerformExamineSearch(long pageIndex, int pageSize, out long totalRecords,
                                                                 string orderBy, Direction orderDirection,
                                                                 string memberTypeAlias, IEnumerable <int> groups,
                                                                 string filter,
                                                                 IDictionary <string, string> additionalFilters = null,
                                                                 bool?isApproved = null, bool?isLockedOut = null)
        {
            if (!(InitialiseMemberQuery() is IQuery query))
            {
                totalRecords = 0;
                return(Enumerable.Empty <ISearchResult>());
            }

            IBooleanOperation op = null;

            if (!memberTypeAlias.IsNullOrWhiteSpace())
            {
                op = query.NodeTypeAlias(memberTypeAlias);
            }

            if (groups?.Any() ?? false)
            {
                // Get group names from ids.
                var groupNames = memberGroupService.GetByIds(groups).Select(x => x.Name);
                if (groupNames.Any())
                {
                    // Keywords need to be all lowercase for Examine 2.0
                    op = query.And(op).GroupedOr(new[] { Constants.Members.Groups }, groupNames.Select(g => new ExamineValue(Examineness.Escaped, g.ToLower())).Cast <IExamineValue>().ToArray());
                }
            }

            if (isApproved.HasValue)
            {
                op = query.And(op).BooleanField(Conventions.Member.IsApproved, isApproved.Value);
            }

            if (isLockedOut.HasValue)
            {
                op = query.And(op).BooleanField(Conventions.Member.IsLockedOut, isLockedOut.Value);
            }

            var basicFields = new List <string>()
            {
                "id", "__NodeId", "__Key", "email", "loginName"
            };

            var filterParameters = additionalFilters.Where(q => q.Key.StartsWith("f_") && !string.IsNullOrWhiteSpace(q.Value));

            //build a lucene query
            if (op == null && string.IsNullOrWhiteSpace(filter) && !filterParameters.Any())
            {
                // Generic get everything (theoretically we shouldn't even get here)...
                op = query.NativeQuery("a* b* c* d* e* f* g* h* i* j* k* l* m* n* o* p* q* r* s* t* u* v* w* x* y* z*");
            }
            else
            {
                if (!filter.IsNullOrWhiteSpace())
                {
                    // the __nodeName will be boosted 10x without wildcards
                    // then __nodeName will be matched normally with wildcards
                    // the rest will be normal without wildcards
                    if (!string.IsNullOrWhiteSpace(filter))
                    {
                        var sb = new StringBuilder();
                        sb.Append("+(");
                        //node name exactly boost x 10
                        sb.AppendFormat("__nodeName:{0}^10.0 ", filter.ToLower());

                        //node name normally with wildcards
                        sb.AppendFormat(" __nodeName:{0}* ", filter.ToLower());

                        foreach (var field in basicFields)
                        {
                            //additional fields normally
                            sb.AppendFormat("{0}:{1} ", field, filter);
                        }
                        sb.Append(")");
                        op = query.And(op).NativeQuery(sb.ToString());
                    }
                }


                // Now specific field searching. - these should be ANDed and grouped.
                foreach (var qs in filterParameters)
                {
                    string alias = qs.Key;
                    if (alias.StartsWith("f_"))
                    {
                        alias = qs.Key.Substring(2);
                    }

                    var values = qs.Value.Split(',');
                    if (values.Length > 0)
                    {
                        op = query.And(op).GroupedOr(new[] { alias }, values);
                    }
                }
            }


            //// Order the results
            // Examine Sorting seems too unreliable, particularly on nodeName
            IOrdering ordering;

            if (orderDirection == Direction.Ascending)
            {
                ordering = op.OrderBy(new SortableField(orderBy.ToLower() == "name" ? "nodeName" : orderBy, SortType.String));
            }
            else
            {
                ordering = op.OrderByDescending(new SortableField(orderBy.ToLower() == "name" ? "nodeName" : orderBy, SortType.String));
            }

#if NET5_0_OR_GREATER
            QueryOptions options = new(0, (int)(pageSize * (pageIndex + 1)));
            var          results = ordering.Execute(options);
#else
            var results = ordering.Execute((int)(pageSize * (pageIndex + 1)));
#endif
            totalRecords = results.TotalItemCount;


            if (pageSize > 0)
            {
                int skipCount = (pageIndex > 0 && pageSize > 0) ? Convert.ToInt32((pageIndex - 1) * pageSize) : 0;
                if (totalRecords < skipCount)
                {
                    skipCount = (int)totalRecords / pageSize;
                }

                return(results.Skip(skipCount).Take(pageSize));
            }

            return(results);
        }