public IActionResult Index(IFormCollection form)
        {
            ConnectionSettings connectionSettings = new ConnectionSettings(new Uri("http://10.1.9.180:9200"));

            connectionSettings.DefaultIndex("product_pool");
            var mapping = this.client.Instance.GetMapping(new GetMappingRequest(Nest.Indices.Index("product_pool")));

            List <KeyValuePair <string, string> > FieldList = mapping.Indices.First().Value.Mappings.Values.First().Properties.Select(x => new KeyValuePair <string, string>(x.Key.Name, x.Value.Type))
                                                              .ToList();
            SearchDescriptor <Dictionary <string, object> > search = new SearchDescriptor <Dictionary <string, object> >();

            search = search.Index("product_pool");
            search = search.AllTypes();
            var qr = new QueryContainerDescriptor <Dictionary <string, object> >();

            QueryContainer queryContainer = new QueryContainer();

            foreach (var itePair in form.Where(x => !string.IsNullOrEmpty(x.Value)).ToList())
            {
                if (FieldList.Any(x => x.Key == itePair.Key.Replace("searchKey_", "")))
                {
                    queryContainer &= qr.Term(itePair.Key.Replace("searchKey_", ""), itePair.Value[0]);
                }
            }

            search.Query(descriptor => queryContainer);
            var documents = this.client.Instance.Search <Dictionary <string, object> >(search);

            //var documents = this.client.Instance.Search<Dictionary<string, object>>(new SearchRequest() { Query = queryContainer });

            //var documents = this.client.Instance.Search<Dictionary<string, object>>(x => x.Index("product_pool").AllTypes().MatchAll());
            var model = new SearchViewModel
            {
                Documents = documents.Hits.Select(x => x.Source).ToList(),
                FieldList = FieldList
            };

            return(View(model));
        }
Пример #2
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);
        }
Пример #3
0
        internal IQueryResponse <Dictionary <string, object> > Execute(ElasticSearchQuery query, Type resultType)
        {
            var index = _context.Index as ElasticSearchIndex;

            if (index == null)
            {
                return(new QueryResponse <Dictionary <string, object> >());
            }

            var descriptor = new SearchDescriptor <Dictionary <string, object> >();

            descriptor.Query(query.Query);

            //TODO: need to determine how to allow type specification, so that we don't have to hard-code AllTypes
            //NEST generates the search query URL based on the descriptor type, so if we use Dictionary<string, object> as the descriptor type, the query URL is:
            //http://[server]:9200/[indexname]/dictionary`2s/_search
            //instead we want it to be:
            //http://[server]:9200/[indexname]/_search
            //when searching over all types. so basically, we want the default to AllTypes unless a specific type is used.
            //In the context of Sitecore search, is it even possible to specify a type for the search? probably, but would need some sort of type mapping...
            descriptor.AllTypes();

            if (query.Filter != null)
            {
                descriptor.Filter(filterDescriptor => filterDescriptor.Query(q => query.Filter));
            }

            if (!Settings.DefaultLanguage.StartsWith(_cultureCode))
            {
                descriptor.Filter(f => f.Query(q => q.Term("_language", _cultureCode)));
            }

            var isResultsSizeSet = false;

            if (query.Methods != null)
            {
                var fields = new List <string>();

                var selectMethods = (from m in query.Methods
                                     where m.MethodType == QueryMethodType.Select
                                     select(SelectMethod) m).ToList <SelectMethod>();

                if (selectMethods.Any())
                {
                    foreach (var method in selectMethods)
                    {
                        fields.AddRange(method.FieldNames.Select(fieldName => fieldName.ToLowerInvariant()));
                    }

                    if (!_context.SecurityOptions.HasFlag(SearchSecurityOptions.DisableSecurityCheck))
                    {
                        fields.Add("_uniqueid");
                        fields.Add("_datasource");
                    }
                }

                var getResultsMethods = (from m in query.Methods
                                         where m.MethodType == QueryMethodType.GetResults
                                         select(GetResultsMethod) m).ToList <GetResultsMethod>();

                if (getResultsMethods.Any())
                {
                    if (fields.Count > 0)
                    {
                        fields.Add("score");
                    }
                }

                if (fields.Count > 0)
                {
                    descriptor.Fields(fields.ToArray());
                }

                var orderByMethods = (from m in query.Methods
                                      where m.MethodType == QueryMethodType.OrderBy
                                      select(OrderByMethod) m).ToList <OrderByMethod>();

                if (orderByMethods.Any())
                {
                    foreach (var method in orderByMethods)
                    {
                        var fieldName = method.Field;
                        switch (method.SortDirection)
                        {
                        case SortDirection.Ascending:
                            descriptor.SortAscending(fieldName);
                            break;

                        case SortDirection.Descending:
                            descriptor.SortDescending(fieldName);
                            break;
                        }
                    }
                }

                var skipMethods = (from m in query.Methods
                                   where m.MethodType == QueryMethodType.Skip
                                   select(SkipMethod) m).ToList <SkipMethod>();

                if (skipMethods.Any())
                {
                    var num = skipMethods.Sum(skipMethod => skipMethod.Count);
                    descriptor.Skip(num);
                }

                var takeMethods = (from m in query.Methods
                                   where m.MethodType == QueryMethodType.Take
                                   select(TakeMethod) m).ToList <TakeMethod>();

                if (takeMethods.Any())
                {
                    var num2 = takeMethods.Sum(takeMethod => takeMethod.Count);
                    descriptor.Size(num2);                     //Take is actually just an alias for Size in NEST, so just use Size instead.
                    isResultsSizeSet = true;
                }

                var countMethods = (from m in query.Methods
                                    where m.MethodType == QueryMethodType.Count
                                    select(CountMethod) m).ToList <CountMethod>();

                if (query.Methods.Count == 1 && countMethods.Any())
                {
                    descriptor.Size(0);                     //TODO: is using Size appropriate here? and is "0" the proper value to send?
                    isResultsSizeSet = true;
                }

                var anyMethods = (from m in query.Methods
                                  where m.MethodType == QueryMethodType.Any
                                  select(AnyMethod) m).ToList <AnyMethod>();

                if (query.Methods.Count == 1 && anyMethods.Any())
                {
                    descriptor.Size(0);                     //TODO: is using Size appropriate here? and is "0" the proper value to send?
                    isResultsSizeSet = true;
                }

                var getFacetsMethods = (from m in query.Methods
                                        where m.MethodType == QueryMethodType.GetFacets
                                        select(GetFacetsMethod) m).ToList <GetFacetsMethod>();

                //TODO: implement facet querying
                if ((query.FacetQueries.Count > 0) && (getFacetsMethods.Any() || getResultsMethods.Any()))
                {
                    //foreach (var facetQuery in GetFacetsPipeline.Run(new GetFacetsArgs(null, query.FacetQueries, _context.Index.Configuration.VirtualFieldProcessors, _context.Index.FieldNameTranslator)).FacetQueries.ToHashSet())
                    //{
                    //	if (!facetQuery.FieldNames.Any())
                    //		continue;

                    //	var nullable = facetQuery.MinimumResultCount;
                    //	if (facetQuery.FieldNames.Count() == 1)
                    //	{
                    //		var fieldNameTranslator = FieldNameTranslator as ElasticSearchFieldNameTranslator;
                    //		var indexFieldName = facetQuery.FieldNames.First();
                    //		if (((fieldNameTranslator != null) && (indexFieldName == fieldNameTranslator.StripKnownExtensions(indexFieldName))) && (_context.Index.Configuration.FieldMap.GetFieldConfiguration(indexFieldName) == null))
                    //		{
                    //			indexFieldName = fieldNameTranslator.GetIndexFieldName(indexFieldName.Replace("__", "!").Replace("_", " ").Replace("!", "__"), true);
                    //		}
                    //		IElasticSearchFacetQuery[] queries = new IElasticSearchFacetQuery[1];
                    //		ElasticSearchFacetFieldQuery query2 = new ElasticSearchFacetFieldQuery(indexFieldName)
                    //			{
                    //				MinCount = nullable
                    //			};
                    //		queries[0] = query2;
                    //		options.AddFacets(queries);
                    //	}
                    //	if (facetQuery.FieldNames.Any())
                    //	{
                    //		IElasticSearchFacetQuery[] queryArray2 = new IElasticSearchFacetQuery[1];
                    //		ElasticSearchFacetPivotQuery query3 = new ElasticSearchFacetPivotQuery
                    //			{
                    //				Fields = new[] { string.Join(",", facetQuery.FieldNames) },
                    //				MinCount = nullable
                    //			};
                    //		queryArray2[0] = query3;
                    //		options.AddFacets(queryArray2);
                    //	}
                    //}
                }
            }

            if (!isResultsSizeSet)
            {
                descriptor.Size(ContentSearchConfigurationSettings.SearchMaxResults);
            }

            //var blee = JsonConvert.SerializeObject(descriptor, Formatting.Indented);

            var serializedDescriptor = index.Client.Serialize(descriptor);

            SearchLog.Log.Info("Serialized Query - " + serializedDescriptor);

            var response = index.Client.Search(descriptor);

            if (!response.ConnectionStatus.Success)
            {
                SearchLog.Log.Error("Query exception - " + response.ConnectionStatus.Error.OriginalException);
            }

            return(response);
        }