Exclude field from search

Vote:
 

Hi

Is it possible to exclude a field in the index from search. The reason is that i want the value LinkUrl to be a part of the index because I need it in my searchresult, but I do not want to search in it. 

I.e a search for "Pages" or "Templates" would yield an enormous amount of hits.

Is this possible to achieve?

#74913
Sep 11, 2013 14:33
Vote:
 

You should be able to add JsonIgnore attribute on the property to exclude it or setup a convention and use the ExcludeField() extension method.

Frederik

#74939
Sep 11, 2013 19:01
Vote:
 

One way would be no enumerate all fields in type and include all excluding LinkUrl.

var q = SearchClient.Instance.Search<PageData>().For("foo").InField(x => x.ExternalURL).InField(x => x.Name);

    

Which is a but cumbersome. Maybe this tiny helper method may come handy:

public static class IQueriedSearchExtensions
{
    public static IQueriedSearch<TSource, QueryStringQuery> ExcludeFields<TSource>(
            this IQueriedSearch<TSource, QueryStringQuery> search,
            params Expression<Func<TSource, string>>[] fieldSelectors)
    {
        var excludedFields = fieldSelectors.Select(fs => fs.GetFieldPath());
        var properties = TypeDescriptor.GetProperties(typeof(TSource));
        var includingFields = properties.Cast<PropertyDescriptor>().Select(p => p.Name).Except(excludedFields);

        includingFields.ForEach(name => search = search.InField(name));
        return search;
    }
}

    

Then you can type something like similar:

var q = SearchClient.Instance.Search<ArticlePage>().For("adsf").ExcludeFields(x => x.LinkURL, x => x.Name);

    

#74940
Sep 11, 2013 23:12
Vote:
 

Hi

 

Frederik: Wouldn't JsonIgnore remove the value from the index? I want the value in the index, but I do not want to search in it. 

Valdis: I will check your method out. Thank you.

 

#74956
Sep 12, 2013 13:50
Vote:
 

Valdis: I can not get this to work properly. The code seems to just remove all hits for some reason. When I debug I can see that your code includes i.e the field MainIntro and I know the text I'm searching for is in that field, but still no hits.

 

To clearify:

 

When i use 

_client.Instance().Search<IBasePageData>(Language.Norwegian)
.For(searchParameters.Query)
.InField(x => x.MainIntro);

it gets the result that I'm excpecting.

 

When I use 

_client.Instance().Search<IBasePageData>(Language.Norwegian)
.For(searchParameters.Query)
.ExcludeFields(x => x.LinkURL);

There is no hits at all.

 

Do you have any idea what is happening?

#74961
Sep 12, 2013 15:00
Vote:
 

The ExcludeFields helper method is wrong as the field name in the index isn't .GetFieldPath() but:

client.Instance().Conventions.FieldNameConvention
.GetFieldNameForSearch(fieldSelector, Language.Norwegian);

It isn't straight forward writing the ExcludeFields as you have to get the right fieldnames for the includingFields as well. I would say that your best option is to use InFields(x => x.MainIntro, x=> ...)


 

#75082
Sep 17, 2013 11:21
Vote:
 

Oh I see, and yes as Henrik said - it would be easier not to try to float against the stream :) and use InField/s() methods.

Anyway, if you are willing to take ExcludeFields approach here is a snippet to be enchanced further (generates correct field names):

public static class IQueriedSearchExtensions
{
    public static IQueriedSearch<TSource, QueryStringQuery> ExcludeFields<TSource>(
            this IQueriedSearch<TSource, QueryStringQuery> search,
            params Expression<Func<TSource, object>>[] fieldSelectors)
    {
        var excludedFields = fieldSelectors.Select(fs => SearchClient.Instance.Conventions.FieldNameConvention.GetFieldNameForSearch(fs, Language.Norwegian));

        var properties = TypeDescriptor.GetProperties(typeof(TSource));
        var lambdaExpressions =
                properties.Cast<PropertyDescriptor>()
                        .Select(pd => Expression.Lambda(Expression.PropertyOrField(Expression.Parameter(typeof(TSource)), pd.Name)));

        var includedFields =
                lambdaExpressions.Select(z1 => SearchClient.Instance.Conventions.FieldNameConvention.GetFieldNameForSearch(z1, Language.Norwegian))
                        .Except(excludedFields);

        includedFields.ForEach(name => search = search.InField(name));
        return search;
    }
}

    

 

There is small side effect for this approach - if you are search for string query and include "$number" field - you most probably will get NumberFormatException. So you would need to exclude all those field as well which may end up with almost the same code as for InFields :) just inverted

#75093
Sep 17, 2013 15:05
Vote:
 

Hi!

The only way we have been successful with excluding properties in EPiServer Find is with [JsonIgnore] and Searchable(false). Without Searchable(false) JsonIgnore doesn't work.

[JsonIgnore]
[Display(
            Name = "Some Field not 2 show",
            GroupName = SystemTabNames.Content,
            Order = 600), Searchable(false)]
public virtual XhtmlString HiddenFromSearchResults { get; set; }

#119598
Mar 31, 2015 10:48
Vote:
 

Hi,

I can give a short comment about the difference between [JsonIgnore] and Searchable(false).

[JsonIgnore]: this removes the property from beeing serialized and put in the index (as a HiddenFromSearchResults property in the json)
Searchable(false/true): This tells if the property should be searchable or not using the internal search and is also used for Find UnifiedSearch. As for Find all the searchable properties are mapped into the SearchText property of the ISearchContent interface (and therefore are searchable even if the HiddenFromSearchResult property isn't serialized and indexed).

So if you want to include/exclude properties from UnifiedSearch you only have to set Searchable(true/false) but if you want to completly exclude it from the index you also have to mark it as [JsonIgnore].

/Henrik

#119621
Edited, Mar 31, 2015 16:57
Vote:
 

@Henrik Lindström: While we are on the subject, would it be possible to exclude a field from being searched via [Searchable(false)] but still have that property map to SearchText? Specifically, we need to exclude the content of a specific page type from being searchable from UnifiedSearch while still maintaining its excerpt.

#119658
Apr 01, 2015 8:31
Vote:
 

@anders.jansson No, not without manully adding the text to the excerpt in the result. The simplest way to do that is to add the property that you want to get back but not have searchable into the SearchMetaData dictionary:

client.Conventions.UnifiedSearchRegistry
.ForInstanceOf<MyType>()
.CustomizeProjection(
builder => builder.ProjectMetaDataFrom<NativeSearchContent>(x => x.SearchMetaData.AppendRange(new Dictionary<string, IndexValue> { { "key", x.MyProperty } })));

Then you can add it to the excerpt manually when fetching the result by grabbing it from the MetaData-property:

hit.MetaData["key"]

/Henrik

#119677
Apr 01, 2015 14:33
Vote:
 

@Henrik Lindström I suppose that's a reasonable workaround. Thanks!

#119680
Apr 01, 2015 14:51
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.