Aricie
The DNN Expert for your web project
Aricie Blog

Providers in LuceneSearch: part 2 - pretenders and replacements

Dec 20 2012

Previously...

In the first part, we saw how a provider could complete the information sent by a module via its ISearchable interface. But the provider system can also be used to replace the search dataset of a module or create it from scratch.

Replacing the search behavior for a module

Our previous example was simply about extending what was returned from the HTML module. But we're not very satisfied with what is coming back from the HTML module. It is so long! So we will split every HTML search item returned into sentences.

How does that work; to act as a search data replacement, a provider must implement the same interface as the module, ISearchable. He must then return a list of SearchItemInfo, as the module would.

    public class HTMLProvider : ILuceneSearchableUpgrade, ILuceneFieldGlossary, ISearchable
    {
        private static readonly string ServerNameField = "ServerName";

        public SearchItemInfoCollection GetSearchItems(ModuleInfo ModInfo)
        {
            var overridenResults = new SearchItemInfoCollection();

            var SearchableModule = ReflectionHelper.CreateObject(ModInfo.DesktopModule.BusinessControllerClass) as ISearchable; 
            if (SearchableModule != null)
            {
                foreach (SearchItemInfo SII in SearchableModule.GetSearchItems(ModInfo))
                {
                    overridenResults.AddRange(SII.Content.Split('.').Select(sentence => new SearchItemInfo(SII.Title, SII.Description, SII.Author, SII.PubDate, SII.ModuleId, SII.SearchKey, sentence)).ToArray());
                }
            }
            return overridenResults;
        }
		// SNIP...

Here we look at everything the HTML module would have sent back, and we replace the data with search items which are composed only of sentences. We are returning a list of SearchItemInfo, but if you want to be more detailed, you can use a LuceneSearchItemInfo directly; the LuceneSearchItemInfo inherits from SearchItemInfo and can be used in its place. Our next step is to configure the provider and tell him to replace the module search data with its own. To do that, we must edit the provider configuration file Aricie.LuceneSearchResults.config and change the configuration we created in the previous post by editing our provider entry to:

    <luceneproviderconfig xsi:type="LuceneModuleProviderConfig">
        DNN HTML Provider
        true
        Upgrade provider for DNN HTML
        HTMLSampleProvider.HTMLProvider, HTMLSampleProvider
        HTML
        true
    
Using a provider to replace the search data coming from a module can be a great way to compensate for some errors or undesired behaviors in the search code; for example the DotNetNuke forum never deletes messages from its search index - even when they are deleted; this behavior wasn't working with LuceneSearch so we had to create a custom provider to take this into account. Usually, though, you should rely on the native ISearchable implementations in modules.

Replacement is not the only option you have. If you decide to set the DiscardNativeProvider to false in the provider configuration, the results coming from the provider and the results coming from the module will be merged and you will get both in your search index.

Pretending to be a module search behavior

We've seen that a provider can replace the search data a module returns, but what's even more interesting is that the same code can provide you with a way to link modules which are not searchable to the DotNetNuke search. This is done with the following steps :

  • Make the provider ISearchable, just as in the example above
  • Configure the provider by setting the ModuleName xml value to the name of the module you want to plus into the search system

The code in the provider is up to you and how you want to retrieve the data from the module. You can for example use the controller from the module:

    public class LegacyModuleProvider : ISearchable
    {
        public SearchItemInfoCollection GetSearchItems(ModuleInfo ModInfo)
        {
            var results = new SearchItemInfoCollection();

            var ctrl = new LegacyModuleController();
            foreach (LegacyElement LE in ctrl.GetLegacyElements())
            {
                results.Add(new SearchItemInfo(LE.Name, LE.Meta, -1, LE.Created, ModInfo.ModuleID, LE.PathToElement, LE.Content));
            }

            return results;
        }
    }

Then you just have to configure it correctly in the xml configuration file:

    <luceneproviderconfig xsi:type="LuceneModuleProviderConfig">
        Legacy module Provider
        true
        Search data provider for our legacy module (cannot change code since Alan lost source code)
        SampleProvider.LegacyModuleProvider, SampleProvider <!-- the full name of your provider -->
LegacyModule <!-- this is where you reference your module by its name -->
true

ISearchable and ILuceneSearchableUpgrade: timing is everything

In the first part, we looked at the upgrading process a provider can run and now we've seen the replacement process. However deciding what type of provider to choose for a module is not as straightforward as checking whether a module is searchable. The ISearchable and ILuceneSearchableUpgrade are called at different times:

  • The ISearchable interface is called during a first pass to retrieve all data from all modules and providers; as such, it should avoid long processing times because there is no upper limit to what timespan is allocated to this operation.
  • The ILuceneSearchableUpgrade interface is called during a second pass; each portal is granted a limited timespan to upgrade its items (this value is configured in the LuceneSearch interface). If the timespan expires while items are still waiting to be upgraded, they are skipped and will be prioritized during the next indexation.

So unless they are extremely important, you should defer time-intensive operations to the upgrade in a provider and keep the search items list creation as lean as possible. For example document indexation should be set in an upgrade step since opening and parsing the document content are very time-consuming. The ISearchable interface should only handle the list of documents to be analyzed.

Conclusion

We've now seen how the LuceneSearch providers can complement, replace or uplift your DotNetNuke modules. In the next part, we will leave the modules behind and venture in the realm of standalone providers. The gloves are off. Stay tuned!

Bloggers
Jesse's blog
 Jesse
 1  9  12/6/2014
Musings without a muse
 samyb
 6  95  1/3/2013
Stephane DNN Blog
 Stéphane TETARD
 1  3  4/23/2012
Categories