Exemple #1
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <param name="indexerName">Name of the indexer for which this DocumentWriting event is being executed on</param>
        private static void DocumentWriting(object sender, DocumentWritingEventArgs e, string indexerName)
        {
            IPublishedContent publishedContent = null;

            var indexerConfiguration = LookService.GetIndexerConfiguration(indexerName);

            if (indexerConfiguration.ShouldIndexContent) // attempt to get content
            {
                publishedContent = LookService.Instance._umbracoHelper.TypedContent(e.NodeId);
            }

            if (publishedContent == null && indexerConfiguration.ShouldIndexMedia) // attempt to get as media
            {
                publishedContent = LookService.Instance._umbracoHelper.TypedMedia(e.NodeId);
            }

            if (publishedContent == null && indexerConfiguration.ShouldIndexMembers) // attempt to get as member
            {
                publishedContent = LookService.Instance._umbracoHelper.SafeTypedMember(e.NodeId);
            }

            if (publishedContent != null)
            {
                var indexingContext = new IndexingContext(null, publishedContent, indexerName);

                LookService.EnsureContext();

                LookService.Index(indexingContext, e.Document);
            }
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <param name="indexerName">Name of the indexer for which this DocumentWriting event is being executed on</param>
        private static void DocumentWriting(object sender, DocumentWritingEventArgs e, string indexerName)
        {
            IPublishedContent publishedContent = null;

            if (LookService.Instance._umbracoHelper == null)
            {
                throw new Exception("Unexpected null value for UmbracoHelper - Look not initialized");
            }

            publishedContent = LookService.Instance._umbracoHelper.TypedContent(e.NodeId);

            if (publishedContent == null)
            {
                // attempt to get as media
                publishedContent = LookService.Instance._umbracoHelper.TypedMedia(e.NodeId);

                if (publishedContent == null)
                {
                    // attempt to get as member
                    publishedContent = LookService.Instance._umbracoHelper.SafeTypedMember(e.NodeId);
                }
            }

            if (publishedContent != null)
            {
                var indexingContext = new IndexingContext(
                    hostNode: null,
                    node: publishedContent,
                    indexerName: indexerName);

                LookService.EnsureContext();

                LookService.Index(indexingContext, e.Document);
            }
        }
        private static void IndexDate(IndexingContext indexingContext, Document document)
        {
            if (indexingContext.Cancelled)
            {
                return;
            }

            DateTime?date = null;

            var dateIndexer = LookService.GetDateIndexer(indexingContext.IndexerName);

            if (dateIndexer != null)
            {
                try
                {
                    date = dateIndexer(indexingContext);
                }
                catch (Exception exception)
                {
                    LogHelper.WarnWithException(typeof(LookService), "Error in date indexer", exception);
                }
            }
            else if (indexingContext.Item != null)
            {
                date = indexingContext.HostItem?.UpdateDate ?? indexingContext.Item.UpdateDate;
            }

            if (date != null)
            {
                var hasDateField = new Field(
                    LookConstants.HasDateField,
                    "1",
                    Field.Store.NO,
                    Field.Index.NOT_ANALYZED);

                var dateValue = DateTools.DateToString(date.Value, DateTools.Resolution.SECOND);

                var dateField = new Field(
                    LookConstants.DateField,
                    dateValue,
                    Field.Store.YES,
                    Field.Index.ANALYZED,
                    Field.TermVector.YES);

                var dateSortedField = new Field(
                    LuceneIndexer.SortedFieldNamePrefix + LookConstants.DateField,
                    dateValue,
                    Field.Store.NO,
                    Field.Index.NOT_ANALYZED,
                    Field.TermVector.NO);

                document.Add(hasDateField);
                document.Add(dateField);
                document.Add(dateSortedField);
            }
        }
Exemple #4
0
        /// <summary>
        /// Set all examine indexers (this may be called from the Hook indexing startup event)
        /// </summary>
        internal static void SetExamineIndexers()
        {
            // get all examine indexer names
            var examineIndexerNames = ExamineManager
                                      .Instance
                                      .IndexProviderCollection
                                      .Select(x => x as BaseUmbracoIndexer)   // UmbracoContentIndexer, UmbracoMemberIndexer
                                      .Where(x => x != null)
                                      .Select(x => x.Name)
                                      .ToArray();

            LookService.SetExamineIndexers(examineIndexerNames);
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <param name="indexerName">Name of the indexer for which this DocumentWriting event is being executed on</param>
        private static void DocumentWriting(object sender, DocumentWritingEventArgs e, string indexerName)
        {
            IPublishedContent publishedContent = null;

            if (LookService.Instance._umbracoHelper == null)
            {
                throw new Exception("Unexpected null value for UmbracoHelper - Look not initialized");
            }

            publishedContent = LookService.Instance._umbracoHelper.TypedContent(e.NodeId);

            if (publishedContent == null)
            {
                // attempt to get as media
                publishedContent = LookService.Instance._umbracoHelper.TypedMedia(e.NodeId);

                if (publishedContent == null)
                {
                    // attempt to get as member
                    publishedContent = LookService.Instance._umbracoHelper.SafeTypedMember(e.NodeId);
                }
            }

            if (publishedContent != null)
            {
                var dummyHttpContext = new HttpContextWrapper(new HttpContext(new SimpleWorkerRequest("", "", new StringWriter())));

                UmbracoContext.EnsureContext(
                    dummyHttpContext,
                    ApplicationContext.Current,
                    new WebSecurity(dummyHttpContext, ApplicationContext.Current),
                    UmbracoConfig.For.UmbracoSettings(),
                    UrlProviderResolver.Current.Providers,
                    true,
                    false);

                var indexingContext = new IndexingContext(
                    hostNode: null,
                    node: publishedContent,
                    indexerName: indexerName);

                LookService.Index(indexingContext, e.Document);
            }
        }
Exemple #6
0
        private static void IndexText(IndexingContext indexingContext, Document document)
        {
            if (indexingContext.Cancelled)
            {
                return;
            }

            var textIndexer = LookService.GetTextIndexer(indexingContext.IndexerName);

            if (textIndexer != null)
            {
                string text = null;

                try
                {
                    text = textIndexer(indexingContext);
                }
                catch (Exception exception)
                {
                    LogHelper.WarnWithException(typeof(LookService), "Error in text indexer", exception);
                }

                if (text != null)
                {
                    var hasTextField = new Field(
                        LookConstants.HasTextField,
                        "1",
                        Field.Store.NO,
                        Field.Index.NOT_ANALYZED);

                    var textField = new Field(
                        LookConstants.TextField,
                        text,
                        Field.Store.YES,
                        Field.Index.ANALYZED,
                        Field.TermVector.YES);

                    document.Add(hasTextField);
                    document.Add(textField);
                }
            }
        }
Exemple #7
0
        private static void IndexTags(IndexingContext indexingContext, Document document)
        {
            if (indexingContext.Cancelled)
            {
                return;
            }

            var tagIndexer = LookService.GetTagIndexer(indexingContext.IndexerName);

            if (tagIndexer != null)
            {
                LookTag[] tags = null;

                try
                {
                    tags = tagIndexer(indexingContext);
                }
                catch (Exception exception)
                {
                    LogHelper.WarnWithException(typeof(LookService), "Error in tag indexer", exception);
                }

                if (tags != null)
                {
                    foreach (var tag in tags)
                    {
                        var hasTagsField = new Field(
                            LookConstants.HasTagsField,
                            "1",
                            Field.Store.NO,
                            Field.Index.NOT_ANALYZED);

                        // add all tags to a common field (serialized such that Tag objects can be restored from this)
                        var allTagsField = new Field(
                            LookConstants.AllTagsField,
                            tag.ToString(),
                            Field.Store.YES,
                            Field.Index.NOT_ANALYZED);

                        // add the tag value to a specific field - this is used for searching on
                        var tagField = new Field(
                            LookConstants.TagsField + tag.Group,
                            tag.Name,
                            Field.Store.YES,
                            Field.Index.NOT_ANALYZED);

                        document.Add(hasTagsField);
                        document.Add(allTagsField);
                        document.Add(tagField);
                    }

                    var tagGroups = tags.Select(x => x.Group).Distinct();

                    foreach (var tagGroup in tagGroups)
                    {
                        var tagGroupField = new Field(
                            LookConstants.TagGroupField + tagGroup,
                            "1",
                            Field.Store.NO,
                            Field.Index.NOT_ANALYZED);

                        document.Add(tagGroupField);
                    }
                }
            }
        }
Exemple #8
0
 /// <summary>
 /// Get the BeforeIndexing method for a specifed index
 /// </summary>
 /// <param name="indexerName"></param>
 /// <returns></returns>
 internal static Action <IndexingContext> GetBeforeIndexing(string indexerName)
 {
     return(LookService.GetIndexerConfiguration(indexerName).BeforeIndexing  // indexer specific
            ?? new Action <IndexingContext>(x => { }));                      // not set
 }
Exemple #9
0
        /// <summary>
        /// Set the supplied examine indexers (this may be called by the consumer to specify the Examine indexes to hook into)
        /// </summary>
        /// <param name="examineIndexers">names of Examine indexers to hook into (null or empty array = none)</param>
        internal static void SetExamineIndexers(string[] examineIndexerNames)
        {
            LookService.Instance._examineIndexersConfigured = true; // set flag so that hook indexing startup event doens't reset any conumser set configuration

            // all examine indexers that should be hooked into (string key = indexer name)
            var examineIndexers = new Dictionary <string, BaseUmbracoIndexer>(); // default to empty - ie, no examine indexers to hook into

            if (examineIndexerNames != null && examineIndexerNames.Any())
            {
                // we (might) have indexers to hook into
                examineIndexers = ExamineManager
                                  .Instance
                                  .IndexProviderCollection
                                  .Select(x => x as BaseUmbracoIndexer)   // UmbracoContentIndexer, UmbracoMemberIndexer
                                  .Where(x => x != null)
                                  .Where(x => examineIndexerNames.Contains(x.Name))
                                  .ToDictionary(x => x.Name, x => x);
            }

            // if there are indexers already registered, remove those that are not in the collection
            var removeEvents = LookService
                               .Instance
                               ._examineDocumentWritingEvents
                               .Where(x => !examineIndexers.ContainsKey(x.Key))
                               .ToDictionary(x => x.Key, x => x.Value);

            foreach (var removeEvent in removeEvents)
            {
                var indexer = ExamineManager.Instance.IndexProviderCollection[removeEvent.Key] as BaseUmbracoIndexer;

                indexer.DocumentWriting -= removeEvent.Value;

                LookService.Instance._examineDocumentWritingEvents.Remove(removeEvent.Key);
            }

            // add events if not already registered
            foreach (var examineIndexer in examineIndexers)
            {
                if (!LookService.Instance._examineDocumentWritingEvents.ContainsKey(examineIndexer.Key))
                {
                    EventHandler <DocumentWritingEventArgs> addEvent = (sender, e) => LookService.DocumentWriting(sender, e, examineIndexer.Key);

                    LookService.Instance._examineDocumentWritingEvents[examineIndexer.Key] = addEvent;

                    examineIndexers[examineIndexer.Key].DocumentWriting += addEvent;
                }

                LogHelper.Info(typeof(LookService), $"Hooking into Examine indexer '{ examineIndexer.Key }'");
            }
        }
 internal static Func <IndexingContext, DateTime?> GetDateIndexer(string indexerName)
 {
     return(LookService.GetIndexerConfiguration(indexerName).DateIndexer
            ?? LookService.Instance._defaultDateIndexer);
 }
        private static void IndexLocation(IndexingContext indexingContext, Document document)
        {
            if (indexingContext.Cancelled)
            {
                return;
            }

            var locationIndexer = LookService.GetLocationIndexer(indexingContext.IndexerName);

            if (locationIndexer != null)
            {
                Location location = null;

                try
                {
                    location = locationIndexer(indexingContext);
                }
                catch (Exception exception)
                {
                    LogHelper.WarnWithException(typeof(LookService), "Error in location indexer", exception);
                }

                if (location != null)
                {
                    var hasLocationField = new Field(
                        LookConstants.HasLocationField,
                        "1",
                        Field.Store.NO,
                        Field.Index.NOT_ANALYZED);

                    var locationField = new Field(
                        LookConstants.LocationField,
                        location.ToString(),
                        Field.Store.YES,
                        Field.Index.NOT_ANALYZED);

                    var locationLatitudeField = new Field(
                        LookConstants.LocationField + "_Latitude",
                        NumericUtils.DoubleToPrefixCoded(location.Latitude),
                        Field.Store.YES,
                        Field.Index.NOT_ANALYZED);

                    var locationLongitudeField = new Field(
                        LookConstants.LocationField + "_Longitude",
                        NumericUtils.DoubleToPrefixCoded(location.Longitude),
                        Field.Store.YES,
                        Field.Index.NOT_ANALYZED);

                    document.Add(hasLocationField);
                    document.Add(locationField);
                    document.Add(locationLatitudeField);
                    document.Add(locationLongitudeField);

                    foreach (var cartesianTierPlotter in LookService.Instance._cartesianTierPlotters)
                    {
                        var boxId = cartesianTierPlotter.GetTierBoxId(location.Latitude, location.Longitude);

                        var tierField = new Field(
                            cartesianTierPlotter.GetTierFieldName(),
                            NumericUtils.DoubleToPrefixCoded(boxId),
                            Field.Store.YES,
                            Field.Index.NOT_ANALYZED_NO_NORMS);

                        document.Add(tierField);
                    }
                }
            }
        }
        /// <summary>
        ///  Do the indexing and set the field values onto the Lucene document
        /// </summary>
        /// <param name="indexingContext"></param>
        /// <param name="document"></param>
        internal static void Index(IndexingContext indexingContext, Document document)
        {
            var indexerConfiguration = LookService.GetIndexerConfiguration(indexingContext.IndexerName);

            if (!indexerConfiguration.ShouldIndexAlias(indexingContext.Item?.DocumentTypeAlias))
            {
                indexingContext.Cancel();
                return;
            }

            var stopwatch = Stopwatch.StartNew();

            try
            {
                LookService.GetBeforeIndexing()(indexingContext);
            }
            catch (Exception exception)
            {
                LogHelper.WarnWithException(typeof(LookService), "Error in global BeforeIndexing", exception);
            }

            try
            {
                LookService.GetBeforeIndexing(indexingContext.IndexerName)(indexingContext);
            }
            catch (Exception exception)
            {
                LogHelper.WarnWithException(typeof(LookService), "Error in indexer BeforeIndexing", exception);
            }

            LookService.IndexNode(indexingContext, document);

            LookService.IndexName(indexingContext, document);

            LookService.IndexDate(indexingContext, document);

            LookService.IndexText(indexingContext, document);

            LookService.IndexTags(indexingContext, document);

            LookService.IndexLocation(indexingContext, document);

            try
            {
                LookService.GetAfterIndexing(indexingContext.IndexerName)(indexingContext);
            }
            catch (Exception exception)
            {
                LogHelper.WarnWithException(typeof(LookService), "Error in indexer AfterIndexing", exception);
            }

            try
            {
                LookService.GetAfterIndexing()(indexingContext);
            }
            catch (Exception exception)
            {
                LogHelper.WarnWithException(typeof(LookService), "Error in global AfterIndexing", exception);
            }

            stopwatch.Stop();

            if (!indexingContext.Cancelled)
            {
                LogHelper.Debug(typeof(LookService), () => $"Building Lucene Document for Id='{indexingContext.Item.Id}', Key='{indexingContext.Item.GetGuidKey()}', Name='{indexingContext.Item.Name}' in Index '{ indexingContext.IndexerName }' Took { stopwatch.ElapsedMilliseconds }ms");
            }
        }
Exemple #13
0
        /// <summary>
        /// Perform a Look search
        /// </summary>
        /// <param name="lookQuery">A LookQuery model for the search criteria</param>
        /// <returns>A LookResult model for the search response</returns>
        public static LookResult Search(LookQuery lookQuery)
        {
            // flag to indicate whether there are any query clauses in the supplied LookQuery
            bool hasQuery = lookQuery?.Compiled != null ? true : false;

            if (lookQuery == null)
            {
                return(LookResult.Error("LookQuery object was null"));
            }

            if (lookQuery.SearchingContext == null) // supplied by unit test to skip examine dependency
            {
                // attempt to get searching context from examine searcher name
                lookQuery.SearchingContext = LookService.GetSearchingContext(lookQuery.SearcherName);

                if (lookQuery.SearchingContext == null)
                {
                    return(LookResult.Error("SearchingContext was null"));
                }
            }

            if (lookQuery.Compiled == null)
            {
                BooleanQuery query  = null; // the lucene query being built
                Filter       filter = null; // used for geospatial queries
                Sort         sort   = null;
                Func <string, IHtmlString> getHighlight = x => null;
                Func <int, double?>        getDistance  = x => null;

                query = new BooleanQuery();

                #region RawQuery

                if (!string.IsNullOrWhiteSpace(lookQuery.RawQuery))
                {
                    hasQuery = true;

                    query.Add(
                        new QueryParser(Lucene.Net.Util.Version.LUCENE_29, null, lookQuery.SearchingContext.Analyzer).Parse(lookQuery.RawQuery),
                        BooleanClause.Occur.MUST);
                }

                #endregion

                #region ExamineQuery

                if (lookQuery.ExamineQuery != null)
                {
                    var luceneSearchCriteria = lookQuery.ExamineQuery as LuceneSearchCriteria; // will be of type LookSearchCriteria when using the custom Look indexer/searcher

                    if (luceneSearchCriteria != null && luceneSearchCriteria.Query != null)
                    {
                        hasQuery = true;

                        query.Add(luceneSearchCriteria.Query, BooleanClause.Occur.MUST);
                    }
                }

                #endregion

                #region NodeQuery

                if (lookQuery.NodeQuery != null)
                {
                    hasQuery = true;

                    query.Add(new TermQuery(new Term(LookConstants.HasNodeField, "1")), BooleanClause.Occur.MUST);

                    // HasType
                    if (lookQuery.NodeQuery.Type != null)
                    {
                        query.Add(
                            new TermQuery(
                                new Term(LookConstants.NodeTypeField, lookQuery.NodeQuery.Type.ToString())),
                            BooleanClause.Occur.MUST);
                    }

                    // HasTypeAny
                    if (lookQuery.NodeQuery.TypeAny != null && lookQuery.NodeQuery.TypeAny.Any())
                    {
                        var nodeTypeQuery = new BooleanQuery();

                        foreach (var nodeType in lookQuery.NodeQuery.TypeAny)
                        {
                            nodeTypeQuery.Add(
                                new TermQuery(
                                    new Term(LookConstants.NodeTypeField, nodeType.ToString())),
                                BooleanClause.Occur.SHOULD);
                        }

                        query.Add(nodeTypeQuery, BooleanClause.Occur.MUST);
                    }

                    // Detached
                    switch (lookQuery.NodeQuery.DetachedQuery)
                    {
                    case DetachedQuery.ExcludeDetached:

                        query.Add(
                            new TermQuery(new Term(LookConstants.IsDetachedField, "1")),
                            BooleanClause.Occur.MUST_NOT);

                        break;

                    case DetachedQuery.OnlyDetached:

                        query.Add(
                            new TermQuery(new Term(LookConstants.IsDetachedField, "1")),
                            BooleanClause.Occur.MUST);

                        break;
                    }

                    // HasCulture
                    if (lookQuery.NodeQuery.Culture != null)
                    {
                        query.Add(
                            new TermQuery(
                                new Term(LookConstants.CultureField, lookQuery.NodeQuery.Culture.LCID.ToString())),
                            BooleanClause.Occur.MUST);
                    }

                    // HasCultureAny
                    if (lookQuery.NodeQuery.CultureAny != null && lookQuery.NodeQuery.CultureAny.Any())
                    {
                        var nodeCultureQuery = new BooleanQuery();

                        foreach (var nodeCulture in lookQuery.NodeQuery.CultureAny)
                        {
                            nodeCultureQuery.Add(
                                new TermQuery(
                                    new Term(LookConstants.CultureField, nodeCulture.LCID.ToString())),
                                BooleanClause.Occur.SHOULD);
                        }

                        query.Add(nodeCultureQuery, BooleanClause.Occur.MUST);
                    }

                    // HasAlias
                    if (lookQuery.NodeQuery.Alias != null)
                    {
                        query.Add(
                            new TermQuery(
                                new Term(LookConstants.NodeAliasField, lookQuery.NodeQuery.Alias.ToString())),
                            BooleanClause.Occur.MUST);
                    }

                    // HasAliasAny
                    if (lookQuery.NodeQuery.AliasAny != null && lookQuery.NodeQuery.AliasAny.Any())
                    {
                        var nodeAliasQuery = new BooleanQuery();

                        foreach (var typeAlias in lookQuery.NodeQuery.AliasAny)
                        {
                            nodeAliasQuery.Add(
                                new TermQuery(
                                    new Term(LookConstants.NodeAliasField, typeAlias)),
                                BooleanClause.Occur.SHOULD);
                        }

                        query.Add(nodeAliasQuery, BooleanClause.Occur.MUST);
                    }

                    // Ids
                    if (lookQuery.NodeQuery.Ids != null && lookQuery.NodeQuery.Ids.Any())
                    {
                        if (lookQuery.NodeQuery.NotIds != null)
                        {
                            var conflictIds = lookQuery.NodeQuery.Ids.Where(x => lookQuery.NodeQuery.NotIds.Contains(x));

                            if (conflictIds.Any())
                            {
                                return(LookResult.Error($"Conflict in NodeQuery, Ids: '{ string.Join(",", conflictIds) }' are in both Ids and NotIds"));
                            }
                        }

                        var idQuery = new BooleanQuery();

                        foreach (var id in lookQuery.NodeQuery.Ids)
                        {
                            idQuery.Add(
                                new TermQuery(new Term(LookConstants.NodeIdField, id.ToString())),
                                BooleanClause.Occur.SHOULD);
                        }

                        query.Add(idQuery, BooleanClause.Occur.MUST);
                    }

                    // Keys
                    if (lookQuery.NodeQuery.Keys != null && lookQuery.NodeQuery.Keys.Any())
                    {
                        if (lookQuery.NodeQuery.NotKeys != null)
                        {
                            var conflictKeys = lookQuery.NodeQuery.Keys.Where(x => lookQuery.NodeQuery.NotKeys.Contains(x));

                            if (conflictKeys.Any())
                            {
                                return(LookResult.Error($"Conflict in NodeQuery, keys: '{ string.Join(",", conflictKeys) }' are in both Keys and NotKeys"));
                            }
                        }

                        var keyQuery = new BooleanQuery();

                        foreach (var key in lookQuery.NodeQuery.Keys)
                        {
                            keyQuery.Add(
                                new TermQuery(new Term(LookConstants.NodeKeyField, key.GuidToLuceneString())),
                                BooleanClause.Occur.SHOULD);
                        }

                        query.Add(keyQuery, BooleanClause.Occur.MUST);
                    }

                    // NotId
                    if (lookQuery.NodeQuery.NotId != null)
                    {
                        query.Add(
                            new TermQuery(new Term(LookConstants.NodeIdField, lookQuery.NodeQuery.NotId.ToString())),
                            BooleanClause.Occur.MUST_NOT);
                    }

                    // NotIds
                    if (lookQuery.NodeQuery.NotIds != null && lookQuery.NodeQuery.NotIds.Any())
                    {
                        foreach (var exculudeId in lookQuery.NodeQuery.NotIds)
                        {
                            query.Add(
                                new TermQuery(new Term(LookConstants.NodeIdField, exculudeId.ToString())),
                                BooleanClause.Occur.MUST_NOT);
                        }
                    }

                    // NotKey
                    if (lookQuery.NodeQuery.NotKey != null)
                    {
                        query.Add(
                            new TermQuery(new Term(LookConstants.NodeKeyField, lookQuery.NodeQuery.NotKey.ToString())),
                            BooleanClause.Occur.MUST_NOT);
                    }

                    // NotKeys
                    if (lookQuery.NodeQuery.NotKeys != null && lookQuery.NodeQuery.NotKeys.Any())
                    {
                        foreach (var excludeKey in lookQuery.NodeQuery.NotKeys)
                        {
                            query.Add(
                                new TermQuery(new Term(LookConstants.NodeKeyField, excludeKey.GuidToLuceneString())),
                                BooleanClause.Occur.MUST_NOT);
                        }
                    }
                }

                #endregion

                #region NameQuery

                if (lookQuery.NameQuery != null)
                {
                    hasQuery = true;

                    query.Add(new TermQuery(new Term(LookConstants.HasNameField, "1")), BooleanClause.Occur.MUST);

                    string wildcard1 = null;
                    string wildcard2 = null; // incase Contains specified with StartsWith and/or EndsWith

                    if (!string.IsNullOrEmpty(lookQuery.NameQuery.StartsWith))
                    {
                        if (!string.IsNullOrEmpty(lookQuery.NameQuery.Is))
                        {
                            if (!lookQuery.NameQuery.Is.StartsWith(lookQuery.NameQuery.StartsWith))
                            {
                                return(LookResult.Error("Conflict in NameQuery between Is and StartsWith"));
                            }
                        }
                        else
                        {
                            wildcard1 = lookQuery.NameQuery.StartsWith + "*";
                        }
                    }

                    if (!string.IsNullOrEmpty(lookQuery.NameQuery.EndsWith))
                    {
                        if (!string.IsNullOrEmpty(lookQuery.NameQuery.Is))
                        {
                            if (!lookQuery.NameQuery.Is.EndsWith(lookQuery.NameQuery.EndsWith))
                            {
                                return(LookResult.Error("Conflict in NameQuery between Is and EndsWith"));
                            }
                        }
                        else
                        {
                            if (wildcard1 == null)
                            {
                                wildcard1 = "*" + lookQuery.NameQuery.EndsWith;
                            }
                            else
                            {
                                wildcard1 += lookQuery.NameQuery.EndsWith;
                            }
                        }
                    }

                    if (!string.IsNullOrEmpty(lookQuery.NameQuery.Contains))
                    {
                        if (!string.IsNullOrEmpty(lookQuery.NameQuery.Is))
                        {
                            if (!lookQuery.NameQuery.Is.Contains(lookQuery.NameQuery.Contains))
                            {
                                return(LookResult.Error("Conflict in NameQuery between Is and Contains"));
                            }
                        }
                        else
                        {
                            if (wildcard1 == null)
                            {
                                wildcard1 = "*" + lookQuery.NameQuery.Contains + "*";
                            }
                            else
                            {
                                wildcard2 = "*" + lookQuery.NameQuery.Contains + "*";
                            }
                        }
                    }

                    var nameField = lookQuery.NameQuery.CaseSensitive ? LookConstants.NameField : LookConstants.NameField + "_Lowered";

                    if (wildcard1 != null)
                    {
                        var wildcard = lookQuery.NameQuery.CaseSensitive ? wildcard1 : wildcard1.ToLower();

                        query.Add(new WildcardQuery(new Term(nameField, wildcard)), BooleanClause.Occur.MUST);

                        if (wildcard2 != null)
                        {
                            wildcard = lookQuery.NameQuery.CaseSensitive ? wildcard2 : wildcard2.ToLower();

                            query.Add(new WildcardQuery(new Term(nameField, wildcard)), BooleanClause.Occur.MUST);
                        }
                    }

                    if (!string.IsNullOrEmpty(lookQuery.NameQuery.Is))
                    {
                        var isText = lookQuery.NameQuery.CaseSensitive ? lookQuery.NameQuery.Is : lookQuery.NameQuery.Is.ToLower();

                        query.Add(new TermQuery(new Term(nameField, isText)), BooleanClause.Occur.MUST);
                    }
                }

                #endregion

                #region DateQuery

                if (lookQuery.DateQuery != null)
                {
                    hasQuery = true;

                    query.Add(new TermQuery(new Term(LookConstants.HasDateField, "1")), BooleanClause.Occur.MUST);

                    if (lookQuery.DateQuery.After.HasValue || lookQuery.DateQuery.Before.HasValue)
                    {
                        var includeLower = lookQuery.DateQuery.After == null || lookQuery.DateQuery.Boundary == DateBoundary.Inclusive || lookQuery.DateQuery.Boundary == DateBoundary.BeforeExclusiveAfterInclusive;
                        var includeUpper = lookQuery.DateQuery.Before == null || lookQuery.DateQuery.Boundary == DateBoundary.Inclusive || lookQuery.DateQuery.Boundary == DateBoundary.BeforeInclusiveAfterExclusive;

                        query.Add(
                            new TermRangeQuery(
                                LookConstants.DateField,
                                lookQuery.DateQuery.After.DateToLuceneString() ?? DateTime.MinValue.DateToLuceneString(),
                                lookQuery.DateQuery.Before.DateToLuceneString() ?? DateTime.MaxValue.DateToLuceneString(),
                                includeLower,
                                includeUpper),
                            BooleanClause.Occur.MUST);
                    }
                }

                #endregion

                #region TextQuery

                if (lookQuery.TextQuery != null)
                {
                    hasQuery = true;

                    query.Add(new TermQuery(new Term(LookConstants.HasTextField, "1")), BooleanClause.Occur.MUST);

                    if (!string.IsNullOrWhiteSpace(lookQuery.TextQuery.SearchText))
                    {
                        var queryParser = new QueryParser(Lucene.Net.Util.Version.LUCENE_29, LookConstants.TextField, lookQuery.SearchingContext.Analyzer);

                        Query searchTextQuery = null;

                        try
                        {
                            searchTextQuery = queryParser.Parse(lookQuery.TextQuery.SearchText);
                        }
                        catch
                        {
                            return(LookResult.Error($"Unable to parse LookQuery.TextQuery.SearchText: '{ lookQuery.TextQuery.SearchText }' into a Lucene query"));
                        }

                        if (searchTextQuery != null)
                        {
                            query.Add(searchTextQuery, BooleanClause.Occur.MUST);

                            if (lookQuery.TextQuery.GetHighlight)
                            {
                                var queryScorer = new QueryScorer(searchTextQuery.Rewrite(lookQuery.SearchingContext.IndexSearcher.GetIndexReader()));

                                var highlighter = new Highlighter(new SimpleHTMLFormatter("<strong>", "</strong>"), queryScorer);

                                getHighlight = (x) =>
                                {
                                    var tokenStream = lookQuery.SearchingContext.Analyzer.TokenStream(LookConstants.TextField, new StringReader(x));

                                    var highlight = highlighter.GetBestFragments(
                                        tokenStream,
                                        x,
                                        1,                             // max number of fragments
                                        "...");

                                    return(new HtmlString(highlight));
                                };
                            }
                        }
                    }
                }

                #endregion

                #region TagQuery

                if (lookQuery.TagQuery != null)
                {
                    hasQuery = true;

                    query.Add(new TermQuery(new Term(LookConstants.HasTagsField, "1")), BooleanClause.Occur.MUST);

                    // Has
                    if (lookQuery.TagQuery.Has != null)
                    {
                        query.Add(
                            new TermQuery(new Term(LookConstants.TagsField + lookQuery.TagQuery.Has.Group, lookQuery.TagQuery.Has.Name)),
                            BooleanClause.Occur.MUST);
                    }

                    // Not
                    if (lookQuery.TagQuery.Not != null)
                    {
                        query.Add(
                            new TermQuery(new Term(LookConstants.TagsField + lookQuery.TagQuery.Not.Group, lookQuery.TagQuery.Not.Name)),
                            BooleanClause.Occur.MUST_NOT);
                    }

                    // HasAll
                    if (lookQuery.TagQuery.HasAll != null && lookQuery.TagQuery.HasAll.Any())
                    {
                        foreach (var tag in lookQuery.TagQuery.HasAll)
                        {
                            query.Add(
                                new TermQuery(new Term(LookConstants.TagsField + tag.Group, tag.Name)),
                                BooleanClause.Occur.MUST);
                        }
                    }

                    // HasAllOr
                    if (lookQuery.TagQuery.HasAllOr != null && lookQuery.TagQuery.HasAllOr.Any() && lookQuery.TagQuery.HasAllOr.SelectMany(x => x).Any())
                    {
                        var orQuery = new BooleanQuery();

                        foreach (var tagCollection in lookQuery.TagQuery.HasAllOr)
                        {
                            if (tagCollection.Any())
                            {
                                var allTagQuery = new BooleanQuery();

                                foreach (var tag in tagCollection)
                                {
                                    allTagQuery.Add(
                                        new TermQuery(new Term(LookConstants.TagsField + tag.Group, tag.Name)),
                                        BooleanClause.Occur.MUST);
                                }

                                orQuery.Add(allTagQuery, BooleanClause.Occur.SHOULD);
                            }
                        }

                        query.Add(orQuery, BooleanClause.Occur.MUST);
                    }

                    // HasAny
                    if (lookQuery.TagQuery.HasAny != null && lookQuery.TagQuery.HasAny.Any())
                    {
                        var anyTagQuery = new BooleanQuery();

                        foreach (var tag in lookQuery.TagQuery.HasAny)
                        {
                            anyTagQuery.Add(
                                new TermQuery(new Term(LookConstants.TagsField + tag.Group, tag.Name)),
                                BooleanClause.Occur.SHOULD);
                        }

                        query.Add(anyTagQuery, BooleanClause.Occur.MUST);
                    }

                    // HasAnyAnd
                    if (lookQuery.TagQuery.HasAnyAnd != null && lookQuery.TagQuery.HasAnyAnd.Any())
                    {
                        foreach (var tagCollection in lookQuery.TagQuery.HasAnyAnd)
                        {
                            if (tagCollection.Any())
                            {
                                var anyTagQuery = new BooleanQuery();

                                foreach (var tag in tagCollection)
                                {
                                    anyTagQuery.Add(
                                        new TermQuery(new Term(LookConstants.TagsField + tag.Group, tag.Name)),
                                        BooleanClause.Occur.SHOULD);
                                }

                                query.Add(anyTagQuery, BooleanClause.Occur.MUST);
                            }
                        }
                    }

                    // NotAny
                    if (lookQuery.TagQuery.NotAny != null && lookQuery.TagQuery.NotAny.Any())
                    {
                        foreach (var tag in lookQuery.TagQuery.NotAny)
                        {
                            query.Add(
                                new TermQuery(new Term(LookConstants.TagsField + tag.Group, tag.Name)),
                                BooleanClause.Occur.MUST_NOT);
                        }
                    }
                }

                #endregion

                #region LocationQuery

                if (lookQuery.LocationQuery != null)
                {
                    hasQuery = true;

                    query.Add(new TermQuery(new Term(LookConstants.HasLocationField, "1")), BooleanClause.Occur.MUST);

                    if (lookQuery.LocationQuery.Boundary != null) // limit results within an lat lng fixed view (eg, typical map bounds)
                    {
                        query.Add(
                            new TermRangeQuery(
                                LookConstants.LocationField + "_Latitude",
                                NumericUtils.DoubleToPrefixCoded(lookQuery.LocationQuery.Boundary.LatitudeMin),
                                NumericUtils.DoubleToPrefixCoded(lookQuery.LocationQuery.Boundary.LatitudeMax),
                                true,
                                true),
                            BooleanClause.Occur.MUST);

                        query.Add(
                            new TermRangeQuery(
                                LookConstants.LocationField + "_Longitude",
                                NumericUtils.DoubleToPrefixCoded(lookQuery.LocationQuery.Boundary.LongitudeMin),
                                NumericUtils.DoubleToPrefixCoded(lookQuery.LocationQuery.Boundary.LongitudeMax),
                                true,
                                true),
                            BooleanClause.Occur.MUST);
                    }

                    if (lookQuery.LocationQuery.Location != null) // location set, so can calculate distance
                    {
                        double maxDistance = LookService._maxDistance;

                        if (lookQuery.LocationQuery.MaxDistance != null)
                        {
                            maxDistance = Math.Min(lookQuery.LocationQuery.MaxDistance.GetMiles(), maxDistance);
                        }

                        var distanceQueryBuilder = new DistanceQueryBuilder(
                            lookQuery.LocationQuery.Location.Latitude,
                            lookQuery.LocationQuery.Location.Longitude,
                            maxDistance,
                            LookConstants.LocationField + "_Latitude",
                            LookConstants.LocationField + "_Longitude",
                            LookConstants.LocationTierFieldPrefix,
                            true);

                        filter = distanceQueryBuilder.Filter;

                        if (lookQuery.SortOn == SortOn.Distance)
                        {
                            sort = new Sort(
                                new SortField(
                                    LookConstants.DistanceField,
                                    new DistanceFieldComparatorSource(distanceQueryBuilder.DistanceFilter)));
                        }

                        getDistance = new Func <int, double?>(x =>
                        {
                            if (distanceQueryBuilder.DistanceFilter.Distances.ContainsKey(x))
                            {
                                return(distanceQueryBuilder.DistanceFilter.Distances[x]);
                            }

                            return(null);
                        });
                    }
                }

                #endregion

                if (hasQuery)
                {
                    switch (lookQuery.SortOn)
                    {
                    case SortOn.Name:     // a -> z
                        sort = new Sort(new SortField(LuceneIndexer.SortedFieldNamePrefix + LookConstants.NameField, SortField.STRING));
                        break;

                    case SortOn.DateAscending:     // oldest -> newest
                        sort = new Sort(new SortField(LuceneIndexer.SortedFieldNamePrefix + LookConstants.DateField, SortField.LONG, false));
                        break;

                    case SortOn.DateDescending:     // newest -> oldest
                        sort = new Sort(new SortField(LuceneIndexer.SortedFieldNamePrefix + LookConstants.DateField, SortField.LONG, true));
                        break;

                        // SortOn.Distance already set (if valid)
                    }

                    lookQuery.Compiled = new LookQueryCompiled(
                        lookQuery,
                        query,
                        filter,
                        sort ?? new Sort(SortField.FIELD_SCORE),
                        getHighlight,
                        getDistance);
                }
            }

            if (!hasQuery)
            {
                return(LookResult.Error("No query clauses supplied")); // empty failure
            }

            TopDocs topDocs = lookQuery
                              .SearchingContext
                              .IndexSearcher
                              .Search(
                lookQuery.Compiled.Query,
                lookQuery.Compiled.Filter,
                LookService._maxLuceneResults,
                lookQuery.Compiled.Sort);

            if (topDocs.TotalHits > 0)
            {
                List <Facet> facets = null;

                if (lookQuery.TagQuery != null && lookQuery.TagQuery.FacetOn != null)
                {
                    facets = new List <Facet>();

                    Query facetQuery = lookQuery.Compiled.Filter != null
                                            ? (Query) new FilteredQuery(lookQuery.Compiled.Query, lookQuery.Compiled.Filter)
                                            : lookQuery.Compiled.Query;

                    // do a facet query for each group in the array
                    foreach (var group in lookQuery.TagQuery.FacetOn.TagGroups)
                    {
                        var simpleFacetedSearch = new SimpleFacetedSearch(
                            lookQuery.SearchingContext.IndexSearcher.GetIndexReader(),
                            LookConstants.TagsField + group);

                        var facetResult = simpleFacetedSearch.Search(facetQuery);

                        facets.AddRange(
                            facetResult
                            .HitsPerFacet
                            .Select(
                                x => new Facet()
                        {
                            Tags  = new LookTag[] { new LookTag(group, x.Name.ToString()) },
                            Count = Convert.ToInt32(x.HitCount)
                        }
                                ));
                    }
                }

                return(new LookResult(
                           lookQuery,
                           topDocs,
                           facets != null ? facets.ToArray() : new Facet[] { }));
            }

            return(LookResult.Empty()); // empty success
        }
        /// <summary>
        ///  Do the indexing and set the field values onto the Lucene document
        /// </summary>
        /// <param name="indexingContext"></param>
        /// <param name="document"></param>
        internal static void Index(IndexingContext indexingContext, Document document)
        {
#if DEBUG
            var stopwatch = Stopwatch.StartNew();
#endif
            #region Node

            if (indexingContext.Item != null)
            {
                var publishedItemType = indexingContext?.HostItem?.ItemType ?? indexingContext.Item.ItemType;

                var hasNodeField = new Field(
                    LookConstants.HasNodeField,
                    "1",
                    Field.Store.NO,
                    Field.Index.NOT_ANALYZED);

                var nodeIdField = new Field(
                    LookConstants.NodeIdField,
                    indexingContext.Item.Id.ToString(),
                    Field.Store.YES,
                    Field.Index.NOT_ANALYZED);

                var nodeKeyField = new Field(
                    LookConstants.NodeKeyField,
                    indexingContext.Item.GetGuidKey().GuidToLuceneString(),
                    Field.Store.YES,
                    Field.Index.NOT_ANALYZED);

                var nodeTypeField = new Field(
                    LookConstants.NodeTypeField,
                    publishedItemType.ToString(),
                    Field.Store.YES,
                    Field.Index.NOT_ANALYZED,
                    Field.TermVector.NO);

                var nodeAliasField = new Field(
                    LookConstants.NodeAliasField,
                    indexingContext.Item.DocumentTypeAlias,
                    Field.Store.YES,
                    Field.Index.NOT_ANALYZED,
                    Field.TermVector.NO);

                document.Add(hasNodeField);
                document.Add(nodeIdField);
                document.Add(nodeKeyField);
                document.Add(nodeTypeField);
                document.Add(nodeAliasField);

                if (publishedItemType == PublishedItemType.Content)
                {
                    var culture = indexingContext?.HostItem?.GetCulture() ?? indexingContext.Item.GetCulture();

                    if (culture != null)
                    {
                        var cultureField = new Field(
                            LookConstants.CultureField,
                            culture.LCID.ToString(),
                            Field.Store.YES,
                            Field.Index.NOT_ANALYZED,
                            Field.TermVector.NO);

                        document.Add(cultureField);
                    }
                }

                if (indexingContext.HostItem != null)
                {
                    var isDetachedField = new Field(
                        LookConstants.IsDetachedField,
                        "1",
                        Field.Store.NO,
                        Field.Index.NOT_ANALYZED);

                    // indexing detached item, so store the host context id so we can return the detached item
                    var hostIdField = new Field(
                        LookConstants.HostIdField,
                        indexingContext.HostItem.Id.ToString(),
                        Field.Store.YES,
                        Field.Index.NOT_ANALYZED);

                    document.Add(isDetachedField);
                    document.Add(hostIdField);
                }
            }

            #endregion

            #region Name

            string name = null;

            if (LookService.GetNameIndexer() != null)
            {
                try
                {
                    name = LookService.GetNameIndexer()(indexingContext);
                }
                catch (Exception exception)
                {
                    LogHelper.WarnWithException(typeof(LookService), "Error in name indexer", exception);
                }
            }
            else if (indexingContext.Item != null)
            {
                name = indexingContext.Item.Name;
            }

            if (name != null)
            {
                var hasNameField = new Field(
                    LookConstants.HasNameField,
                    "1",
                    Field.Store.NO,
                    Field.Index.NOT_ANALYZED);

                var nameField = new Field(
                    LookConstants.NameField,
                    name,
                    Field.Store.YES,
                    Field.Index.NOT_ANALYZED,
                    Field.TermVector.YES);

                // field for lower case searching
                var nameFieldLowered = new Field(
                    LookConstants.NameField + "_Lowered",
                    name.ToLower(),
                    Field.Store.NO,
                    Field.Index.NOT_ANALYZED,
                    Field.TermVector.YES);

                var nameSortedField = new Field(
                    LuceneIndexer.SortedFieldNamePrefix + LookConstants.NameField,
                    name.ToLower(),                         // force case insentive sorting
                    Field.Store.NO,
                    Field.Index.NOT_ANALYZED,
                    Field.TermVector.NO);

                document.Add(hasNameField);
                document.Add(nameField);
                document.Add(nameFieldLowered);
                document.Add(nameSortedField);
            }

            #endregion

            #region Date

            DateTime?date = null;

            if (LookService.GetDateIndexer() != null)
            {
                try
                {
                    date = LookService.GetDateIndexer()(indexingContext);
                }
                catch (Exception exception)
                {
                    LogHelper.WarnWithException(typeof(LookService), "Error in date indexer", exception);
                }
            }
            else if (indexingContext.Item != null)
            {
                date = indexingContext.HostItem?.UpdateDate ?? indexingContext.Item.UpdateDate;
            }

            if (date != null)
            {
                var hasDateField = new Field(
                    LookConstants.HasDateField,
                    "1",
                    Field.Store.NO,
                    Field.Index.NOT_ANALYZED);

                var dateValue = DateTools.DateToString(date.Value, DateTools.Resolution.SECOND);

                var dateField = new Field(
                    LookConstants.DateField,
                    dateValue,
                    Field.Store.YES,
                    Field.Index.ANALYZED,
                    Field.TermVector.YES);

                var dateSortedField = new Field(
                    LuceneIndexer.SortedFieldNamePrefix + LookConstants.DateField,
                    dateValue,
                    Field.Store.NO,
                    Field.Index.NOT_ANALYZED,
                    Field.TermVector.NO);

                document.Add(hasDateField);
                document.Add(dateField);
                document.Add(dateSortedField);
            }

            #endregion

            #region Text

            if (LookService.GetTextIndexer() != null)
            {
                string text = null;

                try
                {
                    text = LookService.GetTextIndexer()(indexingContext);
                }
                catch (Exception exception)
                {
                    LogHelper.WarnWithException(typeof(LookService), "Error in text indexer", exception);
                }

                if (text != null)
                {
                    var hasTextField = new Field(
                        LookConstants.HasTextField,
                        "1",
                        Field.Store.NO,
                        Field.Index.NOT_ANALYZED);

                    var textField = new Field(
                        LookConstants.TextField,
                        text,
                        Field.Store.YES,
                        Field.Index.ANALYZED,
                        Field.TermVector.YES);

                    document.Add(hasTextField);
                    document.Add(textField);
                }
            }

            #endregion

            #region Tag

            if (LookService.GetTagIndexer() != null)
            {
                LookTag[] tags = null;

                try
                {
                    tags = LookService.GetTagIndexer()(indexingContext);
                }
                catch (Exception exception)
                {
                    LogHelper.WarnWithException(typeof(LookService), "Error in tag indexer", exception);
                }

                if (tags != null)
                {
                    foreach (var tag in tags)
                    {
                        var hasTagsField = new Field(
                            LookConstants.HasTagsField,
                            "1",
                            Field.Store.NO,
                            Field.Index.NOT_ANALYZED);

                        // add all tags to a common field (serialized such that Tag objects can be restored from this)
                        var allTagsField = new Field(
                            LookConstants.AllTagsField,
                            tag.ToString(),
                            Field.Store.YES,
                            Field.Index.NOT_ANALYZED);

                        // add the tag value to a specific field - this is used for searching on
                        var tagField = new Field(
                            LookConstants.TagsField + tag.Group,
                            tag.Name,
                            Field.Store.YES,
                            Field.Index.NOT_ANALYZED);

                        document.Add(hasTagsField);
                        document.Add(allTagsField);
                        document.Add(tagField);
                    }
                }
            }

            #endregion

            #region Location

            if (LookService.GetLocationIndexer() != null)
            {
                Location location = null;

                try
                {
                    location = LookService.GetLocationIndexer()(indexingContext);
                }
                catch (Exception exception)
                {
                    LogHelper.WarnWithException(typeof(LookService), "Error in location indexer", exception);
                }

                if (location != null)
                {
                    var hasLocationField = new Field(
                        LookConstants.HasLocationField,
                        "1",
                        Field.Store.NO,
                        Field.Index.NOT_ANALYZED);

                    var locationField = new Field(
                        LookConstants.LocationField,
                        location.ToString(),
                        Field.Store.YES,
                        Field.Index.NOT_ANALYZED);

                    var locationLatitudeField = new Field(
                        LookConstants.LocationField + "_Latitude",
                        NumericUtils.DoubleToPrefixCoded(location.Latitude),
                        Field.Store.YES,
                        Field.Index.NOT_ANALYZED);

                    var locationLongitudeField = new Field(
                        LookConstants.LocationField + "_Longitude",
                        NumericUtils.DoubleToPrefixCoded(location.Longitude),
                        Field.Store.YES,
                        Field.Index.NOT_ANALYZED);

                    document.Add(hasLocationField);
                    document.Add(locationField);
                    document.Add(locationLatitudeField);
                    document.Add(locationLongitudeField);

                    foreach (var cartesianTierPlotter in LookService.Instance._cartesianTierPlotters)
                    {
                        var boxId = cartesianTierPlotter.GetTierBoxId(location.Latitude, location.Longitude);

                        var tierField = new Field(
                            cartesianTierPlotter.GetTierFieldName(),
                            NumericUtils.DoubleToPrefixCoded(boxId),
                            Field.Store.YES,
                            Field.Index.NOT_ANALYZED_NO_NORMS);

                        document.Add(tierField);
                    }
                }
            }

            #endregion
#if DEBUG
            stopwatch.Stop();
            LogHelper.Debug(typeof(LookService), $"Building Lucene Document For '{ indexingContext.Item.GetGuidKey() }' Took { stopwatch.ElapsedMilliseconds }ms");
#endif
        }
 /// <summary>
 /// Get indexer specific AfterIndexing
 /// </summary>
 /// <param name="indexerName"></param>
 /// <returns></returns>
 internal static Action <IndexingContext> GetAfterIndexing(string indexerName)
 {
     return(LookService.GetIndexerConfiguration(indexerName).AfterIndexing
            ?? new Action <IndexingContext>(x => { }));
 }
        private static void IndexName(IndexingContext indexingContext, Document document)
        {
            if (indexingContext.Cancelled)
            {
                return;
            }

            string name = null;

            var nameIndexer = LookService.GetNameIndexer(indexingContext.IndexerName);

            if (nameIndexer != null)
            {
                try
                {
                    name = nameIndexer(indexingContext);
                }
                catch (Exception exception)
                {
                    LogHelper.WarnWithException(typeof(LookService), "Error in name indexer", exception);
                }
            }
            else if (indexingContext.Item != null)
            {
                name = indexingContext.Item.Name;
            }

            if (name != null)
            {
                var hasNameField = new Field(
                    LookConstants.HasNameField,
                    "1",
                    Field.Store.NO,
                    Field.Index.NOT_ANALYZED);

                var nameField = new Field(
                    LookConstants.NameField,
                    name,
                    Field.Store.YES,
                    Field.Index.NOT_ANALYZED,
                    Field.TermVector.YES);

                // field for lower case searching
                var nameFieldLowered = new Field(
                    LookConstants.NameField + "_Lowered",
                    name.ToLower(),
                    Field.Store.NO,
                    Field.Index.NOT_ANALYZED,
                    Field.TermVector.YES);

                var nameSortedField = new Field(
                    LuceneIndexer.SortedFieldNamePrefix + LookConstants.NameField,
                    name.ToLower(),                         // force case insentive sorting
                    Field.Store.NO,
                    Field.Index.NOT_ANALYZED,
                    Field.TermVector.NO);

                document.Add(hasNameField);
                document.Add(nameField);
                document.Add(nameFieldLowered);
                document.Add(nameSortedField);
            }
        }
        /// <summary>
        /// Perform a Look search
        /// </summary>
        /// <param name="lookQuery">A LookQuery model for the search criteria</param>
        /// <returns>A LookResult model for the search response</returns>
        internal static LookResult Search(LookQuery lookQuery)
        {
            if (lookQuery == null)
            {
                return(LookResult.Error("LookQuery object was null"));
            }

            if (lookQuery.SearchingContext == null) // supplied by unit test to skip examine dependency
            {
                // attempt to get searching context from examine searcher name
                lookQuery.SearchingContext = LookService.GetSearchingContext(lookQuery.SearcherName);

                if (lookQuery.SearchingContext == null)
                {
                    return(LookResult.Error("SearchingContext was null"));
                }
            }

            if (lookQuery.Compiled == null)
            {
                var parsingContext = new ParsingContext(); // for building/compiling the query

                try
                {
                    LookService.ParseRawQuery(parsingContext, lookQuery);

                    LookService.ParseExamineQuery(parsingContext, lookQuery);

                    LookService.ParseNodeQuery(parsingContext, lookQuery);

                    LookService.ParseNameQuery(parsingContext, lookQuery);

                    LookService.ParseDateQuery(parsingContext, lookQuery);

                    LookService.ParseTextQuery(parsingContext, lookQuery);

                    LookService.ParseTagQuery(parsingContext, lookQuery);

                    LookService.ParseLocationQuery(parsingContext, lookQuery);
                }
                catch (ParsingException parsingException)
                {
                    return(LookResult.Error(parsingException.Message));
                }

                if (parsingContext.HasQuery)
                {
                    lookQuery.Compiled = new LookQueryCompiled(lookQuery, parsingContext);
                }
                else
                {
                    return(LookResult.Error("Unable to compile query - a query clause is required")); // empty failure
                }
            }

            TopDocs topDocs = lookQuery
                              .SearchingContext
                              .IndexSearcher
                              .Search(
                lookQuery.Compiled.Query,
                lookQuery.Compiled.Filter,
                lookQuery.MaxResults,
                lookQuery.Compiled.Sort);

            if (topDocs.TotalHits > 0)
            {
                List <Facet> facets = null;

                if (lookQuery.TagQuery != null && lookQuery.TagQuery.FacetOn != null)
                {
                    facets = new List <Facet>();

                    Query facetQuery = lookQuery.Compiled.Filter != null
                                            ? (Query) new FilteredQuery(lookQuery.Compiled.Query, lookQuery.Compiled.Filter)
                                            : lookQuery.Compiled.Query;

                    // do a facet query for each group in the array
                    foreach (var group in lookQuery.TagQuery.FacetOn.TagGroups)
                    {
                        var simpleFacetedSearch = new SimpleFacetedSearch(
                            lookQuery.SearchingContext.IndexSearcher.GetIndexReader(),
                            LookConstants.TagsField + group);

                        var facetResult = simpleFacetedSearch.Search(facetQuery);

                        facets.AddRange(
                            facetResult
                            .HitsPerFacet
                            .Select(
                                x => new Facet()
                        {
                            Tags  = new LookTag[] { new LookTag(group, x.Name.ToString()) },
                            Count = Convert.ToInt32(x.HitCount)
                        }
                                ));
                    }
                }

                return(new LookResult(
                           lookQuery,
                           topDocs,
                           facets != null ? facets.ToArray() : new Facet[] { }));
            }

            return(LookResult.Empty()); // empty success
        }
 internal static Func <IndexingContext, string> GetTextIndexer(string indexerName)
 {
     return(LookService.GetIndexerConfiguration(indexerName).TextIndexer
            ?? LookService.Instance._defaultTextIndexer);
 }