Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I search/index a custom datasource in Orchard via Lucene?

I am currently working on a site to allow users to search through a custom product catalog. I have been looking around and would love to leverage Orchard CMS to help me develop this site. I have currently gone through Ron Petersons youtube series on custom Orchard Modules and the Skywalker blog series.

I feel like my goal is possible, but I'm looking for some validation on whether my strategy will work within the Orchard framework.

This is my current situation:

  1. I have an default Orchard configuration pointing to a SQL DB (named Product-Orchard)

  2. I have a custom DAL that points to another SQL DB (named Products).

  3. Products are made up of your typical information (Product Name, Description, Price, etc).

  4. The custom DAL has a POCO model called Product (with a Repository to interact with) with the properties Name, Description, Price.

Now, based on the information I read about creating Orchard modules it seems like the method of creating a custom module with custom content is to:

  1. Create a Module through code gen tools (We'll call it ProductModule)

  2. Create a custom Content Part (ProductPart)

  3. Create a custom Content Part Record (ProductPartRecord) to act as the data model for the part.

  4. Create a custom ContentPartHandler (ProductPartHandler) that handles the persistance of the Content Part.

  5. Create a custom Driver that is the entry for preparing the Shapes for rendering of the UI.

  6. Potentially create a Service that interacts with the Drivers?

This is where things start to get jumbled and I'm not sure if this is possible or not. What I would like to do is to create a custom Content Type that is backed by my custom DAL rather than having the data be stored through the ContentPartRecord inside the Product-Orchard DB, but still allow it to be indexed by the Lucene module to allow for searching of the Product catalog.

Is it possible to create a custom ContentType and/or ContentPart that is backed by a different datasource and still leverage the Lucene search capabilities?

In high level terms I'd like a Product ContentType where the ContentItems are actually stored in my secondary database, not the Orchard database (and still want to be able to leverage Lucene search via Projections).

like image 326
Keith Avatar asked Aug 12 '13 14:08

Keith


1 Answers

For those searching for a similar answer, the following solution is what I settled on. There is no easy mechanism I could find to interact with a separate DAL and perform the Lucene indexing.

  1. Create the Orchard Module
  2. Create new Content Part/Type via aMigration
  3. Use Orchard Command infrastructure to import data from your secondary database
  4. Use the OnIndexing event in the Content Part handler to allow Lucene to index your datasource.
  5. Create a lookup property (I called mine ConcreateProperty) that is populated through a Service I created in the module to interact with the secondary DAL in the OnLoaded event.

My final Handler looked like this:

public class HomePartHandler : ContentHandler {
    public HomePartHandler(IRepository<HomePartRecord> repository, IHomeSearchMLSService homeSearchService) {
        Filters.Add(StorageFilter.For(repository));
        OnLoaded<HomePart>((ctx, part) =>
        {
            part.ConcreteProperty = homeSearchService.GetByMlsNumber(part.MlsId) ?? new PropertyDetail();
        });
        OnIndexing<HomePart>((context, homePart) => context.DocumentIndex
         .Add("home_StreetFullName", homePart.Record.StreetFullName).RemoveTags().Analyze().Store()
         .Add("home_City", homePart.Record.City).RemoveTags().Analyze().Store()
         .Add("home_State", homePart.Record.State).RemoveTags().Analyze().Store()
         .Add("home_Zip", homePart.Record.Zip).RemoveTags().Analyze().Store()
         .Add("home_Subdivision", homePart.Record.Subdivision).RemoveTags().Analyze().Store()
         .Add("home_Beds", homePart.Record.Beds).RemoveTags().Analyze().Store()
         .Add("home_Baths", homePart.Record.Baths).RemoveTags().Analyze().Store()
         .Add("home_SquareFoot", homePart.Record.SquareFoot).RemoveTags().Analyze().Store()
         .Add("home_PropertyType", homePart.Record.PropertyType).RemoveTags().Analyze().Store()
         .Add("home_ListPrice", homePart.Record.ListPrice).RemoveTags().Analyze().Store()
         .Add("home_MlsId", homePart.Record.MlsId).RemoveTags().Analyze().Store()
         .Add("home_Latitude", (double)homePart.Record.Latitude).RemoveTags().Analyze().Store()
         .Add("home_Longitude", (double)homePart.Record.Longitude).RemoveTags().Analyze().Store()
          );
    }
}

This allows me to create a search service for searching through all my data and then hook it up to the model via the Concrete Property, which actually works better from a performance standpoint anyway.

like image 169
Keith Avatar answered Nov 08 '22 12:11

Keith