Search is an essential part of any e-commerce application. If you don’t believe me, go to amazon.com. How hard is it to find the search box? Pretty easy, right? If search is essential, we need to make it work pretty well in our applications.
Our Software Design and Development Clinics focus on teaching engineers the real-world development skills that will lead them to be more productive and effective. We believe that the best way to learn is through hands-on projects. In the case of our clinics, we have a reference e-commerce implementation we use to teach many of the concepts we cover.
But this application doesn’t support search, or at least it doesn’t yet. If we wanted to add search functionality, we could use SQL statements to query the product table but that isn’t a great option. SQL “like” statements won’t find misspelled words or do many other things we would expect from a modern search system.
How should we go about adding search to our application? We could use something like full-text search in the database. That might work for very basic use cases, but there are better options out there. For this activity. we are going to use Lucene.net to do the searches. Lucene.net is an open source search library based off of a Java version called Lucene.
We have used Lucene on a few projects here at Don’t Panic Labs. The great thing about Lucene is that it is pretty light-weight for a search solution. No services to set up. No web server to set up. No Java to install.
But before we jump into code, let’s discuss the changes we are going to make to the system.
Where do we start? At the beginning, of course.
Add a NuGet package reference to Lucene.net to our accessors project. You will need to have “include prerelease” checked to pull the Lucene.Net NuGet package that supports .NET Core. You will also need “Lucene.Net.Analysis.Common”.
Configuration for where Lucene should write its index files is already in place with the IndexPath property on the. Config class.
Start by building out the definition for the SearchAccessor. Place this in the Catalog directory in the accessors project.
Create a SearchAccessor that implements ISearchAccessor and implement the RebuildIndex and Search methods in SearchAccessor.
Once we have those in place we need to add some unit tests for the SearchAccessor. Take a few minutes and write a unit test for the SearchAccessor.
Next, update the catalog manager level to support calling our new search accessor. Add a new method to CatalogManager to perform this search, and a method to rebuild the index. These two methods will be broken across two interfaces.
This solution requires a few new data transfer objects (DTO), which are the data we send between layers. These should be placed in the same directory as the IWebStoreCatalogManager contract. The namespace should be DPLRef.eCommerce.Contracts.WebStore.Catalog.
Now go through and implement the two manager methods. They should be pretty basic methods.
We should also add a few unit tests for this code. But for the purpose of this walkthrough, let’s write a single integration test.
Last, we need to update our webstore UI to support our new search interfaces added to our CatalogManager. To accomplish this, we will need to update our UI (a console app).
Add RebuildSearch and Search methods to class Program. These methods will call down into our manager layer to do the work.
This activity is a great example of how our architecture can be extended with minimal effort. We were able to extend the system by only changing one existing piece (CatalogManager). And the change to CatalogManager was only an extension. We added a new SearchAccessor that hid the dependency of Lucene. Based off of our implementation, we should be able to change our search technology without changing anything else in the system.