コード例 #1
0
ファイル: ElasticSearch.cs プロジェクト: ewin66/rockrms
        /// <summary>
        /// Gets the document by identifier.
        /// </summary>
        /// <param name="documentType">Type of the document.</param>
        /// <param name="id">The identifier.</param>
        /// <returns></returns>
        public override IndexModelBase GetDocumentById(Type documentType, string id)
        {
            var indexName = documentType.Name.ToLower();

            var request = new GetRequest(indexName, indexName, id)
            {
            };

            var result = _client.Get <dynamic>(request);

            IndexModelBase document = new IndexModelBase();

            if (result.Source != null)
            {
                Type indexModelType = Type.GetType((string)((JObject)result.Source)["indexModelType"]);

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

            return(document);
        }
コード例 #2
0
        /// <summary>
        /// Converts Lucene document to index model.
        /// </summary>
        /// <param name="query">The query.</param>
        /// <param name="hit">The scoredoc.</param>
        /// <returns>Index model</returns>
        private IndexModelBase LuceneDocToIndexModel(Query query, ScoreDoc hit)
        {
            var doc = _indexSearcher.Doc(hit.Doc);

            IndexModelBase document = new IndexModelBase();

            try
            {
                var hitJsonField = doc.GetField("JSON");
                if (hitJsonField != null)
                {
                    string  hitJson        = hitJsonField.GetStringValue();
                    JObject jObject        = JObject.Parse(hitJson);
                    Type    indexModelType = Type.GetType($"{ jObject["IndexModelType"].ToStringSafe() }, { jObject["IndexModelAssembly"].ToStringSafe() }");

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

                Explanation explanation = _indexSearcher.Explain(query, hit.Doc);
                document["Explain"] = explanation.ToString();
                document.Score      = hit.Score;

                return(document);
            }
            catch { } // ignore if the result if an exception resulted (most likely cause is getting a result from a non-rock index)
            return(null);
        }
コード例 #3
0
ファイル: Lucene.cs プロジェクト: SparkDevNetwork/Rock
        /// <summary>
        /// Indexes the document.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="document">The document.</param>
        /// <param name="indexName">Name of the index.</param>
        /// <param name="mappingType">Type of the mapping.</param>
        public override void IndexDocument <T>(T document, string indexName = null, string mappingType = null)
        {
            try
            {
                Type documentType = document.GetType();
                if (indexName == null)
                {
                    indexName = documentType.Name.ToLower();
                }

                if (mappingType == null)
                {
                    mappingType = documentType.Name.ToLower();
                }

                if (!_indexes.ContainsKey(mappingType))
                {
                    CreateIndex(documentType);
                }

                var index = _indexes[mappingType];

                Document doc = new Document();
                foreach (var typeMappingProperty in index.MappingProperties.Values)
                {
                    TextField textField = new TextField(typeMappingProperty.Name, documentType.GetProperty(typeMappingProperty.Name).GetValue(document, null).ToStringSafe().ToLower(), global::Lucene.Net.Documents.Field.Store.YES);
                    textField.Boost = typeMappingProperty.Boost;
                    doc.Add(textField);
                }

                IndexModelBase docIndexModelBase = document as IndexModelBase;
                string         indexValue        = LuceneID(mappingType, docIndexModelBase.Id);
                doc.AddStringField("type", mappingType, global::Lucene.Net.Documents.Field.Store.YES);
                doc.AddStringField("id", docIndexModelBase.Id.ToString(), global::Lucene.Net.Documents.Field.Store.YES);
                doc.AddStringField("index", indexValue, global::Lucene.Net.Documents.Field.Store.YES);

                // Stores all the properties as JSON to retrieve object on lookup.
                doc.AddStoredField("JSON", document.ToJson());

                // Use the analyzer in fieldAnalyzers if that field is in that dictionary, otherwise use StandardAnalyzer.
                var analyzer = new PerFieldAnalyzerWrapper(defaultAnalyzer: new StandardAnalyzer(_matchVersion, new CharArraySet(_matchVersion, 0, true)), fieldAnalyzers: index.FieldAnalyzers);

                OpenWriter();
                lock ( _lockWriter )
                {
                    if (_writer != null)
                    {
                        _writer.UpdateDocument(new Term("index", indexValue), doc, analyzer);     // Must specify analyzer because the default analyzer that is specified in indexWriterConfig is null.
                    }
                }
            }
            catch (Exception ex)
            {
                HttpContext context2 = HttpContext.Current;
                ExceptionLogService.LogException(ex, context2);
            }
        }
コード例 #4
0
 /// <summary>
 /// Indexes the documents.
 /// </summary>
 /// <param name="document">The document.</param>
 public static void IndexDocument(IndexModelBase document)
 {
     foreach (var indexType in IndexContainer.Instance.Components)
     {
         var component = indexType.Value.Value;
         if (component.IsActive && component.IsConnected)
         {
             component.IndexDocument(document);
         }
     }
 }
コード例 #5
0
        /// <summary>
        /// Deletes the document.
        /// </summary>
        /// <typeparam name="T">IndexModelBase</typeparam>
        /// <param name="document">The document.</param>
        /// <param name="indexName">Name of the index.</param>
        public override void DeleteDocument <T>(T document, string indexName = null)
        {
            if (indexName == null)
            {
                indexName = document.GetType().Name.ToLower();
            }

            IndexModelBase docIndexModelBase = document as IndexModelBase;

            OpenWriter();
            lock ( _lockWriter )
            {
                if (_writer != null)
                {
                    _writer.DeleteDocuments(new Term("index", LuceneID(document.GetType().Name.ToLower(), docIndexModelBase.Id)));
                }
            }
        }
コード例 #6
0
ファイル: ElasticSearch.cs プロジェクト: ewin66/rockrms
        /// <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);
        }