Put a Search Engine in Your Windows 10 Universal (UWP) Applications

Introducing the dtSearch Engine for UWP. Also available from this author (see article for links): the dtSearch Engine for Android and advanced faceted searching using the dtSearch Engine.

This article is in the Product Showcase section for our sponsors at CodeProject. These articles are intended to provide you with information on products and services that we consider useful and of value to developers.

I’ve spent some time working with the dtSearch library to add search functionality to a number of applications on the web and on my Android device. In this article, I’ll show you how to add a simple full-text document search to a Windows 10 Universal application.

Configuration

To get started, I grab a copy of the dtSearch library and native DLL to add to my project. The dtSearch Engine for UWP has two components:

dtSearchUwpApi.dll provides a managed API wrapper around dtSearchEngine_uwp_Win32.dll, with an API that is very similar to the .NET API. I add the managed library as a reference in my project just like any other DLL and add the native DLL to my project and set its "Build Action" property to "Content" so it will deploy with my application.

Figure 1- Native Library reference in my application

I want to build a searchable index of some famous American documents so I can reference them very quickly whenever one of those social media discussions comes up where folks like to reference the laws of the land. I start by copying some of the transcriptions of these famous documents from the United States Archives online and generating some text files or Word docs in a Docs folder in my project. As with the native DLL, I mark each of these documents as "Content" and "Copy if newer". This way, they’re copied into the APPX and will be available in the application folder when the application is deployed. This is important because I want to be able to display the entire document and to highlight search terms.

Figure 2 - Configuration of document content

Indexing Our Documents

Before any search operations can take place, I need dtSearch to build an index of my documents. For this demo, I’ll add the index operation into the application. If my users want to add documents to the index from the running application, then they will need the ability to update the index after adding documents. To implement this, I add a "Build Index" button that will add the contents of my Docs folder to the index. The application can infer the Docs and Index folders’ locations from the standard ApplicationData and Package objects. The index folder has to go under the ApplicationData object’s LocalFolder because it is read/write, and the Docs folder will go under the Package object’s InstalledLocation folder.

With those locations, I can now connect the buildIndexButton_Click event to the dtSearch IndexJob operation. The event handler method starts by defining some other folder location options necessary for dtSearch to be able to build an index:

With these eight lines, I’ve created a job to build the index and instructed it where to write its output. I’ve told it to create the index if it doesn’t exist and to add records to it. The FoldersToIndex collection has one folder, docFolder, that I captured in the constructor of this class and assigned to the deployed location of the Docs folder. The IncludeFilters collection specifies the filename extensions of the documents to index. Finally, the Execute() call builds the index.

Type-Ahead Searching

The dtSearch engine provides a word list feature that can offer some quick type-ahead or intellisense behavior for a term that you are looking for. In my case, I’ll create a search textbox on the page and provide type-ahead lookup as the text in the textbox changes.

Figure 3 - TypeAhead searching from a textbox in a UWP application

I can provide these simple results in a ListBox by configuring the TextChanged eventhandler for the Search Request textbox. Listing the results of the search involves just a few more lines of code:

In this code, I construct a wordListBuilder object at the class level that references the index on disk so I don’t have to re-initialize it on every keypress. The ListWords method grabs the five words before and after the search term in the index. After clearing the fileList ListBox, I populate the ListBox with the words found and the number of occurrences of each word.

Searching Files and Reporting Results

After a search, I want to be able to display the list of documents, so I can locate that term’s use and win my arguments on social media. To search for the request in the textbox, I create a handler for the search button click to perform the search:

This code clears the ListBox that may have contained suggested words or the results from a previous search. Then it creates a SearchJob and initializes the SearchResults to receive the output from the search engine. It points the IndexesToSearch collection at the indexPath created earlier, and defines some sensible limits for the maximum files, the number of files to stop after searching, and the timeout for the search in seconds. Calling the Execute() method executes the search and populates the SearchResults object with the results of the search.

I can then use a standard for-loop to iterate over the SearchResults and place those values into the ListBox in my user interface:

The "If" statement in this block checks that the relevant document records can be read from the index, which should always be the case unless the index has unexpectedly become inaccessible.

Showing Content

Next I’d really like to display the context of the searched terms in the document. I create a final event handler on the SelectionChanged event for the ListBox and use the dtSearch FileConverter to output some nicely formatted HTML with some context highlighting applied to the terms. I add a WebView to my interface and use that to display the output of my highlighting:

This code sets up the FileConverter with the syntax highlighting HTML markup in the BeforeHit and AfterHit properties and HTML as the OutputFormat. After calling Execute(), the FileConverter’s OutputString property has an HTML view of the document, with hits marked, to display in the WebView control using webView.NavigateToString.

Figure 4 - Search result with highlighting

Summary

dtSearch has made it easy for me to add rich search functionality to this project. With additional features like search across fields and faceted search, there are many options for my next project. The evolution of dtSearch to add UWP support along with its other supported frameworks cements its position in my developer toolbox as my go-to search library.

License

Share

About the Author

Jeff Fritz is a senior program manager in Microsoft’s Developer Division working on the .NET Community Team. As a long time web developer and application architect with experience in large and small applications across a variety of verticals, he knows how to build for performance and practicality. Four days a week, you can catch Jeff hosting a live video stream called 'Fritz and Friends' at twitch.tv/csharpfritz. You can also learn from Jeff on WintellectNow and Pluralsight, follow him on twitter @csharpfritz, and read his blog at jeffreyfritz.com