7

I have ContentSearch code that works and runs fine using Lucene. When I switch the configs over to Solr, the query fails, and the logs state that the field I'm using in the query doesn't exist.

[IndexField("tags")]
public IEnumerable<ID> Tags { get; set; }

16644 13:34:20 ERROR Solr Error : ["undefined field tags"] - Query attempted: [((_template:(2d7ad1cb107e44158690c03e0b65f90c) AND -_name:("__Standard Values")) AND tags:(fc8ac78af9aa495fb4ee08aca0444e1b))]

Note that the error says 'undefined field tags', but really, this should be tags_sm when Sitecore adds the suffix to the query. Changing [IndexField("tags")] to [IndexField("tags_sm")] gets it working....but now my code is Search Provider dependent.

Is there something I'm missing to make this work without the suffix? I thought Sitecore would automatically add it in there?

Here is how the query looks:-

var filterPredicate = PredicateBuilder.True<ArticleSearchResultItem>()
                .And(x => x.TemplateId == IArticlePageItemConstants.TemplateId && x.Name != "__Standard Values");

if (parameters.TagId != (ID)null && parameters.TagId != ID.Null)
{
   filterPredicate = filterPredicate.And(x => x.Tags.Contains(parameters.TagId));
}

var queryable = searchContext.GetQueryable<ArticleSearchResultItem>();
var searchResults = queryable
                .Where(filterPredicate);

This is on Sitecore 8.1 Update-2, using Solr 6.1.0. Thanks.

  • I have always had to modify my custom index fields when switching from Lucene to SOLR. I will be interested if is it possible to do it without. I do notice in habitat switching from 8 to 9 (now SOLR) they did not change the field names. github.com/Sitecore/Habitat/blob/master/src/Foundation/Indexing/… – Chris Auer Oct 3 '18 at 17:52
  • Try to change the public IEnumerable<ID> to public IEnumerable<string> or public List<string> – Hishaam Namooya Oct 4 '18 at 20:00
  • I've had the same issue too. Have you tried adding an explicit mapping for IEnumerable<ID> in the config, something like this? <typeMatch type="System.Collections.Generic.IEnumerable`1[Sitecore.Data.ID]" typeName="idCollection" fieldNameFormat="{0}_sm" multiValued="true" settingType="Sitecore.ContentSearch.SolrProvider.SolrSearchFieldConfiguration, Sitecore.ContentSearch.SolrProvider" /> – mikaelnet Feb 26 '19 at 10:02
  • Maybe this can be solved with a type converter too. I haven't tried it, as I've opted for the approach of adding field type, such as _sm. [TypeConverter(typeof(IndexFieldEnumerableConverter))] – mikaelnet Feb 26 '19 at 10:07
  • 1
    The other way is to add "tags" field in solr schema.xml and then use of <copyField source="tags_sm" dest="tags" />. This way you don't need to change your code. – Mohit Dharmadhikari Oct 22 '19 at 10:35
2

You could change the default field mapping in your index configuration (i would create a custom indexconfiguration based on the default):

sitecore/contentSearch/indexConfigurations/defaultSolrIndexConfiguration/fieldMap/typeMatches

and remove the suffix from the format (this example is for text fields, you should change it for ID-types):

before:

<typeMatch 
    typeName="text"                   
    type="System.String"
    fieldNameFormat="{0}_t"
    cultureFormat="_{1}"
    settingType="Sitecore.ContentSearch.SolrProvider.SolrSearchFieldConfiguration, Sitecore.ContentSearch.SolrProvider" />

without suffix:

<typeMatch 
        typeName="text"                   
        type="System.String"
        fieldNameFormat="{0}"
        cultureFormat=""
        settingType="Sitecore.ContentSearch.SolrProvider.SolrSearchFieldConfiguration, Sitecore.ContentSearch.SolrProvider" />
| improve this answer | |
1

You must have a typematch for type IEnumerable<ID> in your index configuration to make this work. So, create a patch file and include typematch from the below list

//Sitecore 8.1
<typeMatch typeName="idIEnumerable"        type="System.Collections.Generic.IEnumerable`1[[Sitecore.Data.ID, Sitecore.Kernel, Version=8.1.0.0, Culture=neutral, PublicKeyToken=null]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"         fieldNameFormat="{0}_sm"  multiValued="true"    settingType="Sitecore.ContentSearch.SolrProvider.SolrSearchFieldConfiguration, Sitecore.ContentSearch.SolrProvider"  />

//Sitecore 9.0.2
<typeMatch typeName="idIEnumerable"        type="System.Collections.Generic.IEnumerable`1[[Sitecore.Data.ID, Sitecore.Kernel, Version=11.1.0.0, Culture=neutral, PublicKeyToken=null]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"        fieldNameFormat="{0}_sm"  multiValued="true"    settingType="Sitecore.ContentSearch.SolrProvider.SolrSearchFieldConfiguration, Sitecore.ContentSearch.SolrProvider"  />

//Sitecore 9.3
<typeMatch typeName="idIEnumerable"        type="System.Collections.Generic.IEnumerable`1[[Sitecore.Data.ID, Sitecore.Kernel, Version=14.0.0.0, Culture=neutral, PublicKeyToken=null]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"        fieldNameFormat="{0}_sm"  multiValued="true"    settingType="Sitecore.ContentSearch.SolrProvider.SolrSearchFieldConfiguration, Sitecore.ContentSearch.SolrProvider"  />

Plesae note: typematch configuration for type IEnumerable<ID> is dependent on Sitecore.Kernel version as AssemblyQualifiedName requires assembly version number in it. If you look at above three configurations you would find different value for Version attribute. If you have different version of Sitecore then make sure you update right value in Version attribute.


Explanation

tags would get converted to tags_sm in query only if there is a typematch found for that particular type. You can find out the same by looking at typematchs section for your index configuration in showconfig.aspx.

enter image description here

Behind the scene SolrSearchConfiguration class reads this configuration and it sets the strongly type by calling Type.GetType(type) and that works fine with simple types like DateTime, Int32, Int64, String, String[], List etc..

enter image description here

But when type is complex such as IEnumerable<ID> then Type.GetType() method expect a AssemblyQualifiedName. You can get AssemblyQualifiedName for any type by just calling type.GetType() method as shown in the below example

using System;
using System.Collections.Generic;

namespace TestApp
{
    class Program
    {
        static void Main(string[] args)
        {
            var ids = new List<Sitecore.Data.ID>();
            
            Console.WriteLine(ids.GetType().AssemblyQualifiedName);

            Console.Read();
        }
    }
}

and output of this is going to be like this -

System.Collections.Generic.List`1[[Sitecore.Data.ID, Sitecore.Kernel, Version=14.0.0.0, Culture=neutral, PublicKeyToken=null]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089

In the above example, I have taken type List<Sitecore.Data.ID> because we can't create direct instance of IEnumerable<Sitecore.Data.ID> so make sure you replace List`1 with IEnumerable`1

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.