Question

I am using SolrNet to index/search data on set of tables.

I have two tables Category and Item.

Both the tables have same fields, Hence i have a base mapping class form which i derive.

[Serializable]
    [XmlRoot(ElementName = "SolrSearchEntity", Namespace = "")]
    [DataContract(Name = "SolrSearchEntity", Namespace = "")]
    public class SolrSearchEntity
    {
        [XmlElement(ElementName = "Id")]
        [DataMember(Name = "Id", IsRequired = true)]
        [SolrUniqueKey("id")]
        public string Id { get; set; }

        [XmlElement(ElementName = "Name")]
        [DataMember(Name = "Name", IsRequired = true)]
        [SolrField("name")]
        public string Name { get; set; }
    }

public class Category : SolrSearchEntity
    {        
    }

    public class Item : SolrSearchEntity
    {
    }

code block for indexing Category data

using (SolrBaseRepository.Instance<Category> repository = new SolrBaseRepository.Instance<Category>())
            {
                var output = ItemStoreDataManager.GetAllCategoryNames(dataAdapter);
                repository.Start();
                var solr = ServiceLocator.Current.GetInstance<ISolrOperations<Category>>();
                solr.AddRange(output);
                solr.Commit();
            }

code block for indexing Item data

using (SolrBaseRepository.Instance<Item> repository = new SolrBaseRepository.Instance<Item>())
                {
                    var output = ItemStoreDataManager.GetAllItemNames(dataAdapter);
                    repository.Start();
                    var solr = ServiceLocator.Current.GetInstance<ISolrOperations<Item>>();
                    solr.AddRange(output);
                    solr.Commit();
                }

My Schema.xml has

 <fields>
    <!-- declare fields of entity class -->
    <field name="id" type="string" indexed="true" stored="true" required="true" multiValued="false" />
    <field name="name" type="text_general" indexed="true" stored="true" omitNorms="true"/>

    <field name="text" type="text_general" indexed="true" stored="false" multiValued="true"/>
    <field name="_version_" type="long" indexed="true" stored="true"/>

  </fields>

Querying for data in Category

  var entities = ItemStoreManager<Category>.Search(keyword); which will internally execute this.

  new SolrBaseRepository.Instance<T>().Start();
  var solr = ServiceLocator.Current.GetInstance<ISolrOperations<T>>();
  var results = solr.Query(keyword);

Strangely, I am getting the records from the Item table.

How would i tell the SolrNet (search engine) to look within the type i have specified.

Or i am indexing correctly in the first place?

Please help.

Thanks,

Was it helpful?

Solution 3

In addition to the suggestion mentioned by Cook,

Add GUID field in SolrSearchEntity

 [XmlElement(ElementName = "UId")]
 [DataMember(Name = "UId", IsRequired = true)]
 [SolrUniqueKey("uid")]
 public Guid UId { get; set; }

Initialise Uid in the constructor

public Item()
{
   Type = "Item";
   UId = Guid.NewGuid();
}

Changes in schema.xml

<fieldType name="uuid" class="solr.UUIDField" indexed="true" />

 <!-- unique field -->
<field name="uid" type="uuid" indexed="true" stored="true" />

<uniqueKey>uid</uniqueKey>

Now the index will not overlap or inconsistent and the search will be narrowed down to the type specified.

OTHER TIPS

While you are separating your data when you are adding it to the index and are querying based a known type on the client, you are storing it all in the same schema in Solr and are not specifying any way to distinguish item from category records in Solr. I would recommend you modify your schema to include a type field which can just be a simple string, such as the following:

 <field name="type" type="string" indexed="true" stored="true" />

Then you will need to the add the type field to your SolrSearchEntity base class and set it appropriately in the Category and Item classes. Something like the following:

[Serializable]
[XmlRoot(ElementName = "SolrSearchEntity", Namespace = "")]
[DataContract(Name = "SolrSearchEntity", Namespace = "")]
public class SolrSearchEntity
{
    [XmlElement(ElementName = "Id")]
    [DataMember(Name = "Id", IsRequired = true)]
    [SolrUniqueKey("id")]
    public string Id { get; set; }

    [XmlElement(ElementName = "Name")]
    [DataMember(Name = "Name", IsRequired = true)]
    [SolrField("name")]
    public string Name { get; set; }

    [SolrField("type")]
    public string Type {get; set;}
}

public class Category : SolrSearchEntity
{        
    public Category()
    {
       Type = "Category";
    }
}

public class Item : SolrSearchEntity
{
    public Item()
    {
        Type = "Item";
    }
}

Then when you run a search if you want to limit your query by a specific type, you can add a filter query like this to only search Items:

var entities = ItemStoreManager<Category>.Search(keyword); 
new SolrBaseRepository.Instance<T>().Start();
var solr = ServiceLocator.Current.GetInstance<ISolrOperations<T>>();
var options = new QueryOptions{ 
  FilterQueries = new ISolrQuery[] { new SolrQueryByField("type","Item")}};
var results = solr.Query(keyword, options);

Additionally, be careful that your id values are not overlapping in your database as that will cause you to only store one instance of an entity (either the category or item, whichever is indexed last).

Finally, I feel your current indexing strategy is sound and would not recommend the use of the DIH. IMO, you will have more control and flexibility using the SolrNet client library. I have had issues with the Data Import Handlers in the past and found the use of SolrNet to much easier to manage and maintain.

For indexing Multiple tables from DB, I would rather go for Solr DIH for its flexibility instead of any Client libraries.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top