Exemple #1
0
        /// <summary>
        /// Returns a list of matching people
        /// </summary>
        /// <param name="searchterm"></param>
        /// <returns></returns>
        public override IQueryable <string> Search(string searchterm)
        {
            // get configured entities and turn it into a list of entity ids
            List <int> entityIds = new List <int>();

            var searchEntitiesSetting = Rock.Web.SystemSettings.GetValue("core_SmartSearchUniversalSearchEntities");

            if (!string.IsNullOrWhiteSpace(searchEntitiesSetting))
            {
                entityIds = searchEntitiesSetting.Split(',').Select(int.Parse).ToList();
            }

            // get the field critiera
            var fieldCriteriaSetting          = Rock.Web.SystemSettings.GetValue("core_SmartSearchUniversalSearchFieldCriteria");
            SearchFieldCriteria fieldCriteria = new SearchFieldCriteria();

            // get the search type
            var searchType = SearchType.Wildcard;

            if (!string.IsNullOrWhiteSpace(Rock.Web.SystemSettings.GetValue("core_SmartSearchUniversalSearchSearchType")))
            {
                searchType = (SearchType)Enum.Parse(typeof(SearchType), Rock.Web.SystemSettings.GetValue("core_SmartSearchUniversalSearchSearchType"));
            }

            if (!string.IsNullOrWhiteSpace(fieldCriteriaSetting))
            {
                foreach (var queryString in fieldCriteriaSetting.ToKeyValuePairList())
                {
                    // check that multiple values were not passed
                    var values = queryString.Value.ToString().Split(',');

                    foreach (var value in values)
                    {
                        fieldCriteria.FieldValues.Add(new FieldValue {
                            Field = queryString.Key, Value = value
                        });
                    }
                }
            }

            var client  = IndexContainer.GetActiveComponent();
            var results = client.Search(searchterm, searchType, entityIds, fieldCriteria);

            // NOTE: Put a bunch of whitespace before and after it so that the Search box shows blank instead of stringified html
            return(results.Select(r => $"                                                                       <data return-type='{r.IndexModelType}' return-id={r.Id}></data><i class='{ r.IconCssClass}'></i> {r.DocumentName}                                                                               ").ToList().AsQueryable());
        }
Exemple #2
0
        /// <summary>
        /// Gets the search result queryable that matches the search term.
        /// </summary>
        /// <param name="searchTerm">The search term used to find results.</param>
        /// <returns>A queryable of index models that match the search term.</returns>
        private List <UniversalSearch.IndexModels.IndexModelBase> GetSearchResults(string searchTerm)
        {
            // get configured entities and turn it into a list of entity ids
            List <int> entityIds = new List <int>();

            var searchEntitiesSetting = Rock.Web.SystemSettings.GetValue("core_SmartSearchUniversalSearchEntities");

            if (!string.IsNullOrWhiteSpace(searchEntitiesSetting))
            {
                entityIds = searchEntitiesSetting.Split(',').Select(int.Parse).ToList();
            }

            // get the field criteria
            var fieldCriteriaSetting          = Rock.Web.SystemSettings.GetValue("core_SmartSearchUniversalSearchFieldCriteria");
            SearchFieldCriteria fieldCriteria = new SearchFieldCriteria();

            // get the search type
            var searchType = SearchType.Wildcard;

            if (!string.IsNullOrWhiteSpace(Rock.Web.SystemSettings.GetValue("core_SmartSearchUniversalSearchSearchType")))
            {
                searchType = ( SearchType )Enum.Parse(typeof(SearchType), Rock.Web.SystemSettings.GetValue("core_SmartSearchUniversalSearchSearchType"));
            }

            if (!string.IsNullOrWhiteSpace(fieldCriteriaSetting))
            {
                foreach (var queryString in fieldCriteriaSetting.ToKeyValuePairList())
                {
                    // check that multiple values were not passed
                    var values = queryString.Value.ToString().Split(',');

                    foreach (var value in values)
                    {
                        fieldCriteria.FieldValues.Add(new FieldValue {
                            Field = queryString.Key, Value = value
                        });
                    }
                }
            }

            var client = IndexContainer.GetActiveComponent();

            return(client.Search(searchTerm, searchType, entityIds, fieldCriteria));
        }
Exemple #3
0
        /// <summary>
        /// Returns a list of matching people
        /// </summary>
        /// <param name="searchterm"></param>
        /// <returns></returns>
        public override IQueryable<string> Search( string searchterm )
        {
            // get configured entities and turn it into a list of entity ids
            List<int> entityIds = new List<int>();

            var searchEntitiesSetting = Rock.Web.SystemSettings.GetValue( "core_SmartSearchUniversalSearchEntities" );

            if ( !string.IsNullOrWhiteSpace( searchEntitiesSetting ) )
            {
                entityIds = searchEntitiesSetting.Split( ',' ).Select( int.Parse ).ToList();
            }

            // get the field critiera
            var fieldCriteriaSetting = Rock.Web.SystemSettings.GetValue( "core_SmartSearchUniversalSearchFieldCriteria" );
            SearchFieldCriteria fieldCriteria = new SearchFieldCriteria();

            // get the search type
            var searchType = SearchType.Wildcard;

            if ( !string.IsNullOrWhiteSpace( Rock.Web.SystemSettings.GetValue( "core_SmartSearchUniversalSearchFieldCriteria" ) ) )
            {
                searchType = (SearchType)Enum.Parse( typeof( SearchType ), Rock.Web.SystemSettings.GetValue( "core_SmartSearchUniversalSearchFieldCriteria" ) );
            }

            if ( !string.IsNullOrWhiteSpace( fieldCriteriaSetting ) )
            {
                foreach ( var queryString in fieldCriteriaSetting.ToKeyValuePairList() )
                {
                    // check that multiple values were not passed
                    var values = queryString.Value.ToString().Split( ',' );

                    foreach ( var value in values )
                    {

                        fieldCriteria.FieldValues.Add( new FieldValue { Field = queryString.Key, Value = value } );
                    }
                }
            }

            var client = IndexContainer.GetActiveComponent();
            var results = client.Search( searchterm, SearchType.Wildcard, entityIds, fieldCriteria );

            return results.Select( r => $"                                                                       <data return-type='{r.IndexModelType}' return-id={r.Id}></data><i class='{ r.IconCssClass}'></i> {r.DocumentName}                                                                               " ).ToList().AsQueryable();
        }
        /// <summary>
        /// Performs the search
        /// </summary>
        private void Search( )
        {
            var term = PageParameter( "Q" );

            lResults.Text = string.Empty;

            var searchType = GetAttributeValue( "SearchType" ).ConvertToEnum<SearchType>();

            // get listing of selected entities to search on
            List<int> selectedEntities = GetSearchEntities();

            // get listing of filters to apply
            List<FieldValue> fieldValues = GetFieldFilters( selectedEntities );

            SearchFieldCriteria fieldCriteria = new SearchFieldCriteria();
            fieldCriteria.FieldValues = fieldValues;

            var client = IndexContainer.GetActiveComponent();

            long totalResultsAvailable = 0;

            var results = client.Search( term, searchType, selectedEntities, fieldCriteria, _itemsPerPage, _currentPageNum * _itemsPerPage, out totalResultsAvailable );

            StringBuilder formattedResults = new StringBuilder();
            formattedResults.Append( "<ul class='list-unstyled'>" );

            foreach ( var result in results)
            {
                var formattedResult = result.FormatSearchResult( CurrentPerson );

                if ( formattedResult.IsViewAllowed )
                {
                    formattedResults.Append( string.Format( "{0}", formattedResult.FormattedResult ));

                    if ( GetAttributeValue( "ShowScores" ).AsBoolean() )
                    {
                        formattedResults.Append( string.Format( "<div class='pull-right'><small>{0}</small></div>", result.Score ) );
                    }

                    formattedResults.Append( "<hr />" );
                }
            }

            formattedResults.Append( "</ul>" );

            tbSearch.Text = term;

            lResults.Text = formattedResults.ToString();

            // pageination
            StringBuilder pagination = new StringBuilder();

            // previous button
            if (_currentPageNum == 0 )
            {
                pagination.Append("<li class='disabled'><span><span aria-hidden='true'>&laquo;</span></span></li>");
            }
            else
            {
                pagination.Append( String.Format("<li><a href='{0}'><span><span aria-hidden='true'>&laquo;</span></span></a></li>", BuildUrl(-1)) );
            }

            var paginationOffset = 5;
            var startPage = 1;
            var endPage = paginationOffset * 2;

            if (_currentPageNum >= paginationOffset )
            {
                startPage = _currentPageNum - paginationOffset;
                endPage = _currentPageNum + paginationOffset;
            }

            if ((endPage * _itemsPerPage) > totalResultsAvailable )
            {
                endPage = (int)Math.Ceiling((double)totalResultsAvailable / _itemsPerPage);
            }

            if ( endPage == 1 ) {
                pnlPagination.Visible = false;
                return;
            }

            for ( int i = startPage; i <= endPage; i++ )
            {
                if (_currentPageNum == i )
                {
                    pagination.Append( string.Format( "<li class='active'><span>{0} </span></li>", i ) );
                }
                else
                {
                    pagination.Append( string.Format( "<li><a href='{1}'><span>{0} </span></a></li>", i, BuildUrl((i - _currentPageNum) - 1) ) );
                }
            }

            // next button
            if ( _currentPageNum == endPage )
            {
                pagination.Append( "<li class='disabled'><span><span aria-hidden='true'>&raquo;</span></span></li>" );
            }
            else
            {
                pagination.Append( String.Format( "<li><a href='{0}'><span><span aria-hidden='true'>&raquo;</span></span></a></li>", BuildUrl( 1 ) ) );
            }

            lPagination.Text = pagination.ToString();
        }
Exemple #5
0
        /// <summary>
        /// Searches the specified query.
        /// </summary>
        /// <param name="query">The query.</param>
        /// <param name="searchType">Type of the search.</param>
        /// <param name="entities">The entities.</param>
        /// <param name="fieldCriteria">The field criteria.</param>
        /// <param name="size">The size.</param>
        /// <param name="from">From.</param>
        /// <param name="totalResultsAvailable">The total results available.</param>
        /// <returns></returns>
        public override List <IndexModelBase> Search(string query, SearchType searchType, List <int> entities, SearchFieldCriteria fieldCriteria, int?size, int?from, out long totalResultsAvailable)
        {
            List <IndexModelBase> documents = new List <IndexModelBase>();

            totalResultsAvailable = 0;

            if (_client != null)
            {
                ISearchResponse <dynamic> results       = null;
                List <SearchResultModel>  searchResults = new List <SearchResultModel>();

                QueryContainer queryContainer = new QueryContainer();

                // add and field constraints
                var searchDescriptor = new SearchDescriptor <dynamic>().AllIndices();

                if (entities == null || entities.Count == 0)
                {
                    searchDescriptor = searchDescriptor.AllTypes();
                }
                else
                {
                    var entityTypes = new List <string>();
                    foreach (var entityId in entities)
                    {
                        // get entities search model name
                        var entityType = new EntityTypeService(new RockContext()).Get(entityId);
                        entityTypes.Add(entityType.IndexModelType.Name.ToLower());

                        // check if this is a person model, if so we need to add two model types one for person and the other for businesses
                        // wish there was a cleaner way to do this
                        if (entityType.Guid == SystemGuid.EntityType.PERSON.AsGuid())
                        {
                            entityTypes.Add("businessindex");
                        }
                    }

                    searchDescriptor = searchDescriptor.Type(string.Join(",", entityTypes));     // todo: consider adding indexmodeltype to the entity cache
                }

                QueryContainer matchQuery = null;
                if (fieldCriteria != null && fieldCriteria.FieldValues?.Count > 0)
                {
                    foreach (var match in fieldCriteria.FieldValues)
                    {
                        if (fieldCriteria.SearchType == CriteriaSearchType.Or)
                        {
                            matchQuery |= new MatchQuery {
                                Field = match.Field, Query = match.Value, Boost = match.Boost
                            };
                        }
                        else
                        {
                            matchQuery &= new MatchQuery {
                                Field = match.Field, Query = match.Value
                            };
                        }
                    }
                }

                switch (searchType)
                {
                case SearchType.ExactMatch:
                {
                    if (!string.IsNullOrWhiteSpace(query))
                    {
                        queryContainer &= new QueryStringQuery {
                            Query = query, AnalyzeWildcard = true
                        };
                    }

                    // special logic to support emails
                    if (query.Contains("@"))
                    {
                        queryContainer |= new QueryStringQuery {
                            Query = "email:" + query, Analyzer = "whitespace"
                        };                                                                                                    // analyzer = whitespace to keep the email from being parsed into 3 variables because the @ will act as a delimitor by default
                    }

                    // special logic to support phone search
                    if (query.IsDigitsOnly())
                    {
                        queryContainer |= new QueryStringQuery {
                            Query = "phone:*" + query + "*", AnalyzeWildcard = true
                        };
                    }

                    // add a search for all the words as one single search term
                    queryContainer |= new QueryStringQuery {
                        Query = query, AnalyzeWildcard = true, PhraseSlop = 0
                    };

                    if (matchQuery != null)
                    {
                        queryContainer &= matchQuery;
                    }

                    if (size.HasValue)
                    {
                        searchDescriptor.Size(size.Value);
                    }

                    if (from.HasValue)
                    {
                        searchDescriptor.From(from.Value);
                    }

                    searchDescriptor.Query(q => queryContainer);

                    results = _client.Search <dynamic>(searchDescriptor);
                    break;
                }

                case SearchType.Fuzzy:
                {
                    results = _client.Search <dynamic>(d =>
                                                       d.AllIndices().AllTypes()
                                                       .Query(q =>
                                                              q.Fuzzy(f => f.Value(query)
                                                                      .Rewrite(RewriteMultiTerm.TopTermsN))
                                                              )
                                                       );
                    break;
                }

                case SearchType.Wildcard:
                {
                    bool enablePhraseSearch = true;

                    if (!string.IsNullOrWhiteSpace(query))
                    {
                        QueryContainer wildcardQuery = null;

                        // break each search term into a separate query and add the * to the end of each
                        var queryTerms = query.Split(' ').Select(p => p.Trim()).ToList();

                        // special logic to support emails
                        if (queryTerms.Count == 1 && query.Contains("@"))
                        {
                            wildcardQuery |= new QueryStringQuery {
                                Query = "email:*" + query + "*", Analyzer = "whitespace"
                            };
                            enablePhraseSearch = false;
                        }
                        else
                        {
                            foreach (var queryTerm in queryTerms)
                            {
                                if (!string.IsNullOrWhiteSpace(queryTerm))
                                {
                                    wildcardQuery &= new QueryStringQuery {
                                        Query = queryTerm + "*", Analyzer = "whitespace", Rewrite = RewriteMultiTerm.ScoringBoolean
                                    };                                                                                                                                             // without the rewrite all results come back with the score of 1; analyzer of whitespaces says don't fancy parse things like check-in to 'check' and 'in'
                                }
                            }

                            // add special logic to help boost last names
                            if (queryTerms.Count > 1)
                            {
                                QueryContainer nameQuery = null;
                                nameQuery &= new QueryStringQuery {
                                    Query = "lastName:" + queryTerms.Last() + "*", Analyzer = "whitespace", Boost = 30
                                };
                                nameQuery &= new QueryStringQuery {
                                    Query = "firstName:" + queryTerms.First() + "*", Analyzer = "whitespace"
                                };
                                wildcardQuery |= nameQuery;
                            }

                            // special logic to support phone search
                            if (query.IsDigitsOnly())
                            {
                                wildcardQuery |= new QueryStringQuery {
                                    Query = "phoneNumbers:*" + query, Analyzer = "whitespace"
                                };
                            }
                        }

                        queryContainer &= wildcardQuery;
                    }

                    // add a search for all the words as one single search term
                    if (enablePhraseSearch)
                    {
                        queryContainer |= new QueryStringQuery {
                            Query = query, AnalyzeWildcard = true, PhraseSlop = 0
                        };
                    }

                    if (matchQuery != null)
                    {
                        queryContainer &= matchQuery;
                    }

                    if (size.HasValue)
                    {
                        searchDescriptor.Size(size.Value);
                    }

                    if (from.HasValue)
                    {
                        searchDescriptor.From(from.Value);
                    }

                    searchDescriptor.Query(q => queryContainer);

                    var indexBoost = GlobalAttributesCache.Value("UniversalSearchIndexBoost");

                    if (indexBoost.IsNotNullOrWhiteSpace())
                    {
                        var boostItems = indexBoost.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
                        foreach (var boostItem in boostItems)
                        {
                            var boostParms = boostItem.Split(new char[] { '^' });

                            if (boostParms.Length == 2)
                            {
                                int boost = 1;
                                Int32.TryParse(boostParms[1], out boost);
                                searchDescriptor.IndicesBoost(b => b.Add(boostParms[0], boost));
                            }
                        }
                    }

                    results = _client.Search <dynamic>(searchDescriptor);
                    break;
                }
                }

                totalResultsAvailable = results.Total;

                // normalize the results to rock search results
                if (results != null)
                {
                    foreach (var hit in results.Hits)
                    {
                        IndexModelBase document = new IndexModelBase();

                        try
                        {
                            if (hit.Source != null)
                            {
                                Type indexModelType = Type.GetType($"{ ((string)((JObject)hit.Source)["indexModelType"])}, { ((string)((JObject)hit.Source)["indexModelAssembly"])}");

                                if (indexModelType != null)
                                {
                                    document = (IndexModelBase)((JObject)hit.Source).ToObject(indexModelType);   // return the source document as the derived type
                                }
                                else
                                {
                                    document = ((JObject)hit.Source).ToObject <IndexModelBase>(); // return the source document as the base type
                                }
                            }

                            if (hit.Explanation != null)
                            {
                                document["Explain"] = hit.Explanation.ToJson();
                            }

                            document.Score = hit.Score;

                            documents.Add(document);
                        }
                        catch { } // ignore if the result if an exception resulted (most likely cause is getting a result from a non-rock index)
                    }
                }
            }

            return(documents);
        }
Exemple #6
0
        /// <summary>
        /// Searches the specified query.
        /// </summary>
        /// <param name="query">The query.</param>
        /// <param name="searchType">Type of the search.</param>
        /// <param name="entities">The entities.</param>
        /// <param name="fieldCriteria">The field criteria.</param>
        /// <param name="size">The size.</param>
        /// <param name="from">From.</param>
        /// <returns></returns>
        public override List <IndexModelBase> Search(string query, SearchType searchType = SearchType.Wildcard, List <int> entities = null, SearchFieldCriteria fieldCriteria = null, int?size = null, int?from = null)
        {
            long totalResultsAvailable = 0;

            return(Search(query, searchType, entities, fieldCriteria, size, from, out totalResultsAvailable));
        }
Exemple #7
0
        /// <summary>
        /// Renders the specified context.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="result">The result.</param>
        public override void Render( Context context, TextWriter result )
        {
            // first ensure that search commands are allowed in the context
            if ( !this.IsAuthorized( context ) )
            {
                result.Write( string.Format( "The Lava command '{0}' is not configured for this template.", this.Name ) );
                base.Render( context, result );
                return;
            }

            var parms = ParseMarkup( _markup, context );

            SearchFieldCriteria fieldCriteria = new SearchFieldCriteria();

            SearchType searchType = SearchType.Wildcard;

            List<int> entityIds = new List<int>();
            string query = string.Empty;

            if (parms.Any( p => p.Key == "query" ) )
            {
                query = parms["query"];
            }

            if ( parms.Any( p => p.Key == "fieldcriteria" ) )
            {
                foreach ( var queryString in parms["fieldcriteria"].ToKeyValuePairList() )
                {
                    // check that multiple values were not passed
                    var values = queryString.Value.ToString().Split( ',' );

                    foreach ( var value in values )
                    {

                        fieldCriteria.FieldValues.Add( new FieldValue { Field = queryString.Key, Value = value } );
                    }
                }
            }

            if ( parms.Any( p => p.Key == "searchtype" ) )
            {
                switch( parms["searchtype"] )
                {
                    case "exactmatch":
                        {
                            searchType = SearchType.ExactMatch;
                            break;
                        }
                    case "fuzzy":
                        {
                            searchType = SearchType.Fuzzy;
                            break;
                        }
                    case "wildcard":
                        {
                            searchType = SearchType.Wildcard;
                            break;
                        }
                }
            }

            if ( parms.Any( p => p.Key == "criteriasearchtype" ) )
            {
                if (parms["criteriasearchtype"].ToLower() == "and" )
                {
                    fieldCriteria.SearchType = CriteriaSearchType.And;
                }
            }

            if ( parms.Any( p => p.Key == "entities" ) )
            {
                var entities = parms["entities"].Split( ',' );

                foreach(var entity in entities )
                {
                    foreach(var entityType in EntityTypeCache.All() )
                    {
                        if (entityType.FriendlyName.ToLower() == entity )
                        {
                            entityIds.Add( entityType.Id );
                        }
                    }
                }
            }

            var client = IndexContainer.GetActiveComponent();
            var results = client.Search( query, searchType, entityIds, fieldCriteria );

            context.Scopes.Last()[parms["iterator"]] = results;

            base.Render( context, result );
        }
Exemple #8
0
        /// <summary>
        /// Searches the specified query.
        /// </summary>
        /// <param name="query">The query.</param>
        /// <param name="searchType">Type of the search.</param>
        /// <param name="entities">The entities.</param>
        /// <param name="fieldCriteria">The field criteria.</param>
        /// <param name="size">The size.</param>
        /// <param name="from">From.</param>
        /// <param name="totalResultsAvailable">The total results available.</param>
        /// <returns></returns>
        public override List <IndexModelBase> Search(string query, SearchType searchType, List <int> entities, SearchFieldCriteria fieldCriteria, int?size, int?from, out long totalResultsAvailable)
        {
            List <IndexModelBase> documents = new List <IndexModelBase>();

            totalResultsAvailable = 0;
            bool allEntities = false;

            BooleanQuery  queryContainer  = new BooleanQuery();
            List <string> combinedFields  = new List <string>();
            List <Type>   indexModelTypes = new List <Type>();
            Dictionary <string, Analyzer> combinedFieldAnalyzers = new Dictionary <string, Analyzer>();

            using (RockContext rockContext = new RockContext())
            {
                var entityTypeService = new EntityTypeService(rockContext);
                if (entities == null || entities.Count == 0)
                {
                    //add all entities
                    allEntities = true;
                    var selectedEntityTypes = EntityTypeCache.All().Where(e => e.IsIndexingSupported && e.IsIndexingEnabled && e.FriendlyName != "Site");

                    foreach (var entityTypeCache in selectedEntityTypes)
                    {
                        entities.Add(entityTypeCache.Id);
                    }
                }

                foreach (var entityId in entities)
                {
                    // get entities search model name
                    var entityType = entityTypeService.GetNoTracking(entityId);
                    indexModelTypes.Add(entityType.IndexModelType);

                    // check if this is a person model, if so we need to add two model types one for person and the other for businesses
                    // wish there was a cleaner way to do this
                    if (entityType.Guid == SystemGuid.EntityType.PERSON.AsGuid())
                    {
                        indexModelTypes.Add(typeof(BusinessIndex));
                    }
                }

                indexModelTypes = indexModelTypes.Distinct().ToList();
                CombineIndexTypes(indexModelTypes, out combinedFields, out combinedFieldAnalyzers);

                if (entities != null && entities.Count != 0 && !allEntities)
                {
                    var indexModelTypesQuery = new BooleanQuery();
                    indexModelTypes.ForEach(f => indexModelTypesQuery.Add(new TermQuery(new Term("type", f.Name.ToLower())), Occur.SHOULD));
                    queryContainer.Add(indexModelTypesQuery, Occur.MUST);
                }
            }

            TopDocs topDocs = null;
            // Use the analyzer in fieldAnalyzers if that field is in that dictionary, otherwise use StandardAnalyzer.
            PerFieldAnalyzerWrapper analyzer = new PerFieldAnalyzerWrapper(defaultAnalyzer: new StandardAnalyzer(_matchVersion), fieldAnalyzers: combinedFieldAnalyzers);

            if (fieldCriteria != null && fieldCriteria.FieldValues?.Count > 0)
            {
                Occur occur = fieldCriteria.SearchType == CriteriaSearchType.And ? Occur.MUST : Occur.SHOULD;
                foreach (var match in fieldCriteria.FieldValues)
                {
                    BooleanClause booleanClause = new BooleanClause(new TermQuery(new Term(match.Field, match.Value)), occur);
                    booleanClause.Query.Boost = match.Boost;
                    queryContainer.Add(booleanClause);
                }
            }

            switch (searchType)
            {
            case SearchType.ExactMatch:
            {
                var wordQuery = new BooleanQuery();

                if (!string.IsNullOrWhiteSpace(query))
                {
                    var words = query.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                    foreach (var word in words)
                    {
                        var innerQuery = new BooleanQuery();
                        combinedFields.ForEach(f => innerQuery.Add(new PrefixQuery(new Term(f, word.ToLower())), Occur.SHOULD));
                        wordQuery.Add(innerQuery, Occur.SHOULD);
                    }
                }

                if (wordQuery.Count() != 0)
                {
                    queryContainer.Add(wordQuery, Occur.MUST);
                }

                // special logic to support emails
                if (query.Contains("@"))
                {
                    queryContainer.Add(new BooleanClause(new TermQuery(new Term("Email", query)), Occur.SHOULD));
                }

                // special logic to support phone search
                if (query.IsDigitsOnly())
                {
                    queryContainer.Add(new BooleanClause(new WildcardQuery(new Term("PhoneNumbers", "*" + query + "*")), Occur.SHOULD));
                }

                // add a search for all the words as one single search term
                foreach (var field in combinedFields)
                {
                    var phraseQuery = new PhraseQuery();
                    phraseQuery.Add(new Term(field, query.ToLower()));
                    queryContainer.Add(phraseQuery, Occur.SHOULD);
                }

                break;
            }

            case SearchType.Fuzzy:
            {
                foreach (var field in combinedFields)
                {
                    queryContainer.Add(new FuzzyQuery(new Term(field, query.ToLower())), Occur.SHOULD);
                }

                break;
            }

            case SearchType.Wildcard:
            {
                bool enablePhraseSearch = true;

                if (!string.IsNullOrWhiteSpace(query))
                {
                    BooleanQuery wildcardQuery = new BooleanQuery();

                    // break each search term into a separate query and add the * to the end of each
                    var queryTerms = query.Split(' ').Select(p => p.Trim()).ToList();

                    // special logic to support emails
                    if (queryTerms.Count == 1 && query.Contains("@"))
                    {
                        wildcardQuery.Add(new WildcardQuery(new Term("Email", "*" + query.ToLower() + "*")), Occur.SHOULD);
                        enablePhraseSearch = false;
                    }
                    else
                    {
                        foreach (var queryTerm in queryTerms)
                        {
                            if (!string.IsNullOrWhiteSpace(queryTerm))
                            {
                                var innerQuery = new BooleanQuery();
                                combinedFields.ForEach(f => innerQuery.Add(new PrefixQuery(new Term(f, queryTerm.ToLower())), Occur.SHOULD));
                                wildcardQuery.Add(innerQuery, Occur.MUST);
                            }
                        }

                        // add special logic to help boost last names
                        if (queryTerms.Count() > 1 && (indexModelTypes.Contains(typeof(PersonIndex)) || indexModelTypes.Contains(typeof(BusinessIndex))))
                        {
                            BooleanQuery nameQuery = new BooleanQuery
                            {
                                { new PrefixQuery(new Term("FirstName", queryTerms.First().ToLower())), Occur.MUST },
                                { new PrefixQuery(new Term("LastName", queryTerms.Last().ToLower()))
                                  {
                                      Boost = 30
                                  }, Occur.MUST }
                            };
                            wildcardQuery.Add(nameQuery, Occur.SHOULD);

                            nameQuery = new BooleanQuery
                            {
                                { new PrefixQuery(new Term("NickName", queryTerms.First().ToLower())), Occur.MUST },
                                { new PrefixQuery(new Term("LastName", queryTerms.Last().ToLower()))
                                  {
                                      Boost = 30
                                  }, Occur.MUST }
                            };
                            wildcardQuery.Add(nameQuery, Occur.SHOULD);
                        }

                        // special logic to support phone search
                        if (query.IsDigitsOnly())
                        {
                            wildcardQuery.Add(new PrefixQuery(new Term("PhoneNumbers", queryTerms.First().ToLower())), Occur.SHOULD);
                        }
                    }

                    queryContainer.Add(wildcardQuery, Occur.MUST);
                }

                // add a search for all the words as one single search term
                if (enablePhraseSearch)
                {
                    // add a search for all the words as one single search term
                    foreach (var field in combinedFields)
                    {
                        var phraseQuery = new PhraseQuery();
                        phraseQuery.Add(new Term(field, query.ToLower()));
                        queryContainer.Add(phraseQuery, Occur.SHOULD);
                    }
                }

                break;
            }
            }

            int returnSize = 10;

            if (size.HasValue)
            {
                returnSize = size.Value;
            }

            OpenReader();

            if (from.HasValue)
            {
                TopScoreDocCollector collector = TopScoreDocCollector.Create(returnSize * 10, true);   // Search for 10 pages with returnSize entries in each page
                _indexSearcher.Search(queryContainer, collector);
                topDocs = collector.GetTopDocs(from.Value, returnSize);
            }
            else
            {
                topDocs = _indexSearcher.Search(queryContainer, returnSize);
            }

            totalResultsAvailable = topDocs.TotalHits;

            if (topDocs != null)
            {
                foreach (var hit in topDocs.ScoreDocs)
                {
                    var document = LuceneDocToIndexModel(queryContainer, hit);
                    if (document != null)
                    {
                        documents.Add(document);
                    }
                }
            }

            return(documents);
        }
Exemple #9
0
        /// <summary>
        /// Renders the specified context.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="result">The result.</param>
        public override void Render(Context context, TextWriter result)
        {
            // first ensure that search commands are allowed in the context
            if (!this.IsAuthorized(context))
            {
                result.Write(string.Format(RockLavaBlockBase.NotAuthorizedMessage, this.Name));
                base.Render(context, result);
                return;
            }

            var parms = ParseMarkup(_markup, context);

            SearchFieldCriteria fieldCriteria = new SearchFieldCriteria();

            SearchType searchType = SearchType.Wildcard;

            List <int> entityIds = new List <int>();
            string     query     = string.Empty;

            int limit  = 50;
            int offset = 0;

            if (parms.Any(p => p.Key == "query"))
            {
                query = parms["query"];
            }

            if (parms.Any(p => p.Key == "limit"))
            {
                Int32.TryParse(parms["limit"], out limit);
            }

            if (parms.Any(p => p.Key == "offset"))
            {
                Int32.TryParse(parms["offset"], out offset);
            }

            if (parms.Any(p => p.Key == "fieldcriteria"))
            {
                foreach (var queryString in parms["fieldcriteria"].ToKeyValuePairList())
                {
                    // check that multiple values were not passed
                    var values = queryString.Value.ToString().Split(',');

                    foreach (var value in values)
                    {
                        // the first letter of the field name should be lowercase
                        string fieldName = Char.ToLowerInvariant(queryString.Key[0]) + queryString.Key.Substring(1);
                        fieldCriteria.FieldValues.Add(new FieldValue {
                            Field = fieldName, Value = value
                        });
                    }
                }
            }

            if (parms.Any(p => p.Key == "searchtype"))
            {
                switch (parms["searchtype"])
                {
                case "exactmatch":
                {
                    searchType = SearchType.ExactMatch;
                    break;
                }

                case "fuzzy":
                {
                    searchType = SearchType.Fuzzy;
                    break;
                }

                case "wildcard":
                {
                    searchType = SearchType.Wildcard;
                    break;
                }
                }
            }

            if (parms.Any(p => p.Key == "criteriasearchtype"))
            {
                if (parms["criteriasearchtype"].ToLower() == "and")
                {
                    fieldCriteria.SearchType = CriteriaSearchType.And;
                }
            }

            if (parms.Any(p => p.Key == "entities"))
            {
                var entities = parms["entities"].Split(',');

                foreach (var entity in entities)
                {
                    foreach (var entityType in EntityTypeCache.All())
                    {
                        if (entityType.FriendlyName?.ToLower() == entity)
                        {
                            entityIds.Add(entityType.Id);
                        }
                    }
                }
            }

            var client  = IndexContainer.GetActiveComponent();
            var results = client.Search(query, searchType, entityIds, fieldCriteria, limit, offset);

            context.Scopes.Last()[parms["iterator"]] = results;

            base.Render(context, result);
        }
        /// <summary>
        /// Performs the search
        /// </summary>
        private void Search( )
        {
            var term = PageParameter("Q");

            lResults.Text = string.Empty;

            var searchType = GetAttributeValue("SearchType").ConvertToEnum <SearchType>();

            // get listing of selected entities to search on
            List <int> selectedEntities = GetSearchEntities();

            // get listing of filters to apply
            List <FieldValue> fieldValues = GetFieldFilters(selectedEntities);

            SearchFieldCriteria fieldCriteria = new SearchFieldCriteria();

            fieldCriteria.FieldValues = fieldValues;

            var client = IndexContainer.GetActiveComponent();

            if (client == null)
            {
                nbWarnings.Text = "No indexing service is currently configured.";
            }
            else
            {
                long totalResultsAvailable = 0;

                var results = client.Search(term, searchType, selectedEntities, fieldCriteria, _itemsPerPage, _currentPageNum * _itemsPerPage, out totalResultsAvailable);

                if (GetAttributeValue("UseCustomResults").AsBoolean())
                {
                    var mergeFields = Rock.Lava.LavaHelper.GetCommonMergeFields(null);
                    mergeFields.Add("Results", results);

                    lResults.Text = GetAttributeValue("LavaResultTemplate").ResolveMergeFields(mergeFields, GetAttributeValue("CustomResultsCommands"));
                }
                else
                {
                    StringBuilder formattedResults = new StringBuilder();
                    formattedResults.Append("<ul class='list-unstyled'>");

                    var showScores = GetAttributeValue("ShowScores").AsBoolean();

                    // for speed we will get the common merge fields and pass them to the formatter so it does not have to be done repeatedly in the loop (it's a bit expensive)
                    var mergeFields = Rock.Lava.LavaHelper.GetCommonMergeFields(null, CurrentPerson);

                    foreach (var result in results)
                    {
                        var formattedResult = result.FormatSearchResult(CurrentPerson, null, mergeFields);

                        if (formattedResult.IsViewAllowed)
                        {
                            formattedResults.Append(string.Format("{0}", formattedResult.FormattedResult));

                            if (showScores)
                            {
                                formattedResults.Append(string.Format("<div class='pull-right'><small>{0}</small></div>", result.Score));
                            }

                            formattedResults.Append("<hr />");
                        }
                    }

                    formattedResults.Append("</ul>");

                    tbSearch.Text = term;
                    lResults.Text = formattedResults.ToString();
                }

                // pagination
                if (totalResultsAvailable > 0)
                {
                    StringBuilder pagination = new StringBuilder();

                    // previous button
                    if (_currentPageNum == 0)
                    {
                        pagination.Append("<li class='disabled'><span><span aria-hidden='true'>&laquo;</span></span></li>");
                    }
                    else
                    {
                        pagination.Append(String.Format("<li><a href='{0}'><span><span aria-hidden='true'>&laquo;</span></span></a></li>", BuildUrl(-1)));
                    }

                    var paginationOffset = 5;
                    var startPage        = 1;
                    var endPage          = paginationOffset * 2;

                    if (_currentPageNum >= paginationOffset)
                    {
                        startPage = _currentPageNum - paginationOffset;
                        endPage   = _currentPageNum + paginationOffset;
                    }

                    if ((endPage * _itemsPerPage) > totalResultsAvailable)
                    {
                        endPage = ( int )Math.Ceiling(( double )totalResultsAvailable / _itemsPerPage);
                    }

                    if (endPage == 1)
                    {
                        pnlPagination.Visible = false;
                        return;
                    }

                    for (int i = startPage; i <= endPage; i++)
                    {
                        if ((_currentPageNum + 1) == i)
                        {
                            pagination.Append(string.Format("<li class='active'><span>{0} </span></li>", i));
                        }
                        else
                        {
                            pagination.Append(string.Format("<li><a href='{1}'><span>{0} </span></a></li>", i, BuildUrl((i - _currentPageNum) - 1)));
                        }
                    }

                    // next button
                    if (_currentPageNum == endPage)
                    {
                        pagination.Append("<li class='disabled'><span><span aria-hidden='true'>&raquo;</span></span></li>");
                    }
                    else
                    {
                        pagination.Append(String.Format("<li><a href='{0}'><span><span aria-hidden='true'>&raquo;</span></span></a></li>", BuildUrl(1)));
                    }

                    lPagination.Text = pagination.ToString();
                }
            }
        }