Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Paul Seal 524 posts 2889 karma points MVP 6x c-trib
    Jul 12, 2017 @ 08:51
    Paul Seal
    0

    Search by member email address domain part

    Hi all I want to be able to search in Umbraco by the domain part of a member's email address.

    I've been advised to add this setting to enable leading wildcards

    <add name="InternalMemberSearcher" type="UmbracoExamine.UmbracoExamineSearcher, UmbracoExamine"
               analyzer="Lucene.Net.Analysis.Standard.StandardAnalyzer, Lucene.Net" enableLeadingWildcard="true"/>
    

    So I've done that, and now I've edited the method in EntitiesController. I've commented above the line I added.

        private IEnumerable<EntityBasic> ExamineSearch(string query, UmbracoEntityTypes entityType, int pageSize, int pageIndex, out int totalFound, string searchFrom = null)
        {
            //TODO: We need to update this to support paging
    
            var sb = new StringBuilder();
    
            string type;
            var searcher = Constants.Examine.InternalSearcher;            
            var fields = new[] { "id", "__NodeId" };
    
            //TODO: WE should really just allow passing in a lucene raw query
            switch (entityType)
            {
                case UmbracoEntityTypes.Member:
                    searcher = Constants.Examine.InternalMemberSearcher;
                    type = "member";
                    fields = new[] { "id", "__NodeId", "email", "loginName"};
                    if (searchFrom != null && searchFrom != Constants.Conventions.MemberTypes.AllMembersListId && searchFrom.Trim() != "-1")
                    {
                        sb.Append("+__NodeTypeAlias:");
                        sb.Append(searchFrom);
                        sb.Append(" ");
                    }
                    break;
                case UmbracoEntityTypes.Media:
                    type = "media";
    
                    var mediaSearchFrom = int.MinValue;
    
                    if (Security.CurrentUser.StartMediaId > 0 ||
                        //if searchFrom is specified and it is greater than 0
                        (searchFrom != null && int.TryParse(searchFrom, out mediaSearchFrom) && mediaSearchFrom > 0))
                    {
                        sb.Append("+__Path: \\-1*\\,");
                        sb.Append(mediaSearchFrom > 0
                            ? mediaSearchFrom.ToString(CultureInfo.InvariantCulture)
                            : Security.CurrentUser.StartMediaId.ToString(CultureInfo.InvariantCulture));
                        sb.Append("\\,* ");
                    }
                    break;
                case UmbracoEntityTypes.Document:
                    type = "content";
    
                    var contentSearchFrom = int.MinValue;
    
                    if (Security.CurrentUser.StartContentId > 0 || 
                        //if searchFrom is specified and it is greater than 0
                        (searchFrom != null && int.TryParse(searchFrom, out contentSearchFrom) && contentSearchFrom > 0))
                    {
                        sb.Append("+__Path: \\-1*\\,");
                        sb.Append(contentSearchFrom > 0
                            ? contentSearchFrom.ToString(CultureInfo.InvariantCulture)
                            : Security.CurrentUser.StartContentId.ToString(CultureInfo.InvariantCulture));
                        sb.Append("\\,* ");
                    }
                    break;
                default:
                    throw new NotSupportedException("The " + typeof(EntityController) + " currently does not support searching against object type " + entityType);                    
            }
    
            var internalSearcher = ExamineManager.Instance.SearchProviderCollection[searcher];
    
            //build a lucene query:
            // the __nodeName will be boosted 10x without wildcards
            // then __nodeName will be matched normally with wildcards
            // the rest will be normal without wildcards
    
    
            //check if text is surrounded by single or double quotes, if so, then exact match
            var surroundedByQuotes = Regex.IsMatch(query, "^\".*?\"$")
                                     || Regex.IsMatch(query, "^\'.*?\'$");
    
            if (surroundedByQuotes)
            {
                //strip quotes, escape string, the replace again
                query = query.Trim(new[] { '\"', '\'' });
    
                query = Lucene.Net.QueryParsers.QueryParser.Escape(query);
    
                //nothing to search
                if (searchFrom.IsNullOrWhiteSpace() && query.IsNullOrWhiteSpace())
                {
                    totalFound = 0;
                    return new List<EntityBasic>();
                }
    
                //update the query with the query term
                if (query.IsNullOrWhiteSpace() == false)
                {
                    //add back the surrounding quotes
                    query = string.Format("{0}{1}{0}", "\"", query);
    
                    //node name exactly boost x 10
                    sb.Append("+(__nodeName: (");
                    sb.Append(query.ToLower());
                    sb.Append(")^10.0 ");
    
                    foreach (var f in fields)
                    {
                        //additional fields normally
                        sb.Append(f);
                        sb.Append(": (");
                        sb.Append(query);
                        sb.Append(") ");
                    }
    
                    sb.Append(") ");
                }
            }
            else
            {
                var trimmed = query.Trim(new[] {'\"', '\''});
    
                //nothing to search
                if (searchFrom.IsNullOrWhiteSpace() && trimmed.IsNullOrWhiteSpace())
                {
                    totalFound = 0;
                    return new List<EntityBasic>();
                }
    
                //update the query with the query term
                if (trimmed.IsNullOrWhiteSpace() == false)
                {
                    query = Lucene.Net.QueryParsers.QueryParser.Escape(query);
    
                    var querywords = query.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
    
                    //node name exactly boost x 10
                    sb.Append("+(__nodeName:");
                    sb.Append("\"");
                    sb.Append(query.ToLower());
                    sb.Append("\"");
                    sb.Append("^10.0 ");
    
                    //node name normally with wildcards
                    sb.Append(" __nodeName:");
                    sb.Append("(");
                    foreach (var w in querywords)
                    {
                        sb.Append(w.ToLower());
                        sb.Append("* ");
                    }
                    sb.Append(") ");
    
    
                    foreach (var f in fields)
                    {
                        //additional fields normally
                        sb.Append(f);
                        sb.Append(":");
                        sb.Append("(");
                        foreach (var w in querywords)
                        {
                            //I added this line below
                            sb.Append("*");
                            sb.Append(w.ToLower());
                            sb.Append("* ");
                        }
                        sb.Append(")");
                        sb.Append(" ");
                    }
    
                    sb.Append(") ");
                }
            }
    
            //must match index type
            sb.Append("+__IndexType:");
            sb.Append(type);
    
            var raw = internalSearcher.CreateSearchCriteria().RawQuery(sb.ToString());
    
            var result = internalSearcher
                //only return the number of items specified to read up to the amount of records to fill from 0 -> the number of items on the page requested
                .Search(raw, pageSize * (pageIndex + 1)); 
    
            totalFound = result.TotalItemCount;
    
            var pagedResult = result.Skip(pageIndex);
    
            switch (entityType)
            {
                case UmbracoEntityTypes.Member:
                    return MemberFromSearchResults(pagedResult.ToArray());
                case UmbracoEntityTypes.Media:
                    return MediaFromSearchResults(pagedResult);                    
                case UmbracoEntityTypes.Document:
                    return ContentFromSearchResults(pagedResult);
                default:
                    throw new NotSupportedException("The " + typeof(EntityController) + " currently does not support searching against object type " + entityType);
            }
        }
    

    It hasn't worked, I get a YSOD error message.

    Please can you help me, or tell me I'm doing it wrong, or point me in the right direction.

  • Damiaan 442 posts 1301 karma points MVP 6x c-trib
    Jul 12, 2017 @ 09:02
    Damiaan
    0

    Do you have a stacktrace?

  • Paul Seal 524 posts 2889 karma points MVP 6x c-trib
    Jul 12, 2017 @ 10:01
    Paul Seal
    0

    I get this if I debug

    Lucene.Net.QueryParsers.ParseException occurred
      HResult=0x80131500
      Message=Cannot parse '+(__nodeName:"gmail"^10.0  __nodeName:(gmail* ) id:(*gmail* ) __NodeId:(*gmail* ) ) +__IndexType:content': '*' or '?' not allowed as first character in WildcardQuery
      Source=Lucene.Net
      StackTrace:
       at Lucene.Net.QueryParsers.QueryParser.Parse(String query)
       at Examine.LuceneEngine.SearchCriteria.LuceneSearchCriteria.RawQuery(String query)
       at Umbraco.Web.Editors.EntityController.ExamineSearch(String query, UmbracoEntityTypes entityType, Int32 pageSize, Int32 pageIndex, Int32& totalFound, String searchFrom) in C:\Users\paul.seal.MEDIANETWORK\Documents\GitHub\Umbraco-CMS\src\Umbraco.Web\Editors\EntityController.cs:line 781
       at Umbraco.Web.Editors.EntityController.ExamineSearch(String query, UmbracoEntityTypes entityType, String searchFrom) in C:\Users\paul.seal.MEDIANETWORK\Documents\GitHub\Umbraco-CMS\src\Umbraco.Web\Editors\EntityController.cs:line 597
       at Umbraco.Web.Editors.EntityController.SearchAll(String query) in C:\Users\paul.seal.MEDIANETWORK\Documents\GitHub\Umbraco-CMS\src\Umbraco.Web\Editors\EntityController.cs:line 118
       at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass10.<GetExecutor>b__9(Object instance, Object[] methodParameters)
       at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken)
    
    Inner Exception 1:
    ParseException: '*' or '?' not allowed as first character in WildcardQuery
    
  • Damiaan 442 posts 1301 karma points MVP 6x c-trib
    Jul 12, 2017 @ 10:08
    Damiaan
    0

    '*' or '?' not allowed as first character in WildcardQuery

    My best guess is that leading wildcards are not allowed in your configuration. If you are using Examine there is an option enableLeadingWildcard in your ExamineSettings.config

    <add name="InternalMemberSearcher" type="UmbracoExamine.UmbracoExamineSearcher, UmbracoExamine"
           analyzer="Lucene.Net.Analysis.Standard.StandardAnalyzer, Lucene.Net" enableLeadingWildcard="true"/>
    
  • Paul Seal 524 posts 2889 karma points MVP 6x c-trib
    Jul 12, 2017 @ 11:02
    Paul Seal
    0

    Hi Damian I've already done that. I put it in the first part of my question.

    Thanks for trying to help me.

    Kind regards

    Paul

  • Ismail Mayat 4511 posts 10090 karma points MVP 2x admin c-trib
    Jul 12, 2017 @ 11:21
    Ismail Mayat
    0

    Paul,

    Why are you searching on _ fields those are not tokensied. So _nodeName should be nodeName. This wont be the error but searching on _ fields which umbraco examine uses for sorting may be give you incorrect results. In fact update to use non _ fields take of the leading wildcard and see if that works.

    You are using standard analyser so it should see the email. If it dont work then we can look at leading wildcard again however get rid of __ fields and replace with actual names.

    Regards

    Ismail

Please Sign in or register to post replies

Write your reply to:

Draft