Let’s write a simple C# program that indexes and searches a data set.
In this guide we will be using BionicSearchLib with a single-file DLL installation. Request Developer Access to obtain your library file.
What you will learn
- Create a simple C# .NET console app
- Run dotnet from terminal or VSCode
- Install BionicSearchLib
- Add and index data
- Set up a search query
You will not need prior C# knowledge to follow this guide, but a basic understanding of programming is required.
Prerequisites:
Make sure you have a BionicSearchLib.dll file. If you dont, Request Developer Access and we’ll supply you one if your application is approved.
Download the data here:
Download airports.txt (2.4mb)
Source files for tutorial in github
Let’s begin 👩🏾💻🧑🏼💻👨🏻💻👩🏽💻👩🏻💻
In this tutorial we will be using 💻 VSCode for Mac.
1 ) Create a new C# console application
Navigate to the directory where you would like to create a new app, and create a new folder with the name of your app. We will call our example SearchConsole
mkdir SearchConsole
Create a new Console App with the dotnet CLI from your shell or terminal
dotnet new console
If your terminal looks like the one above, you are ready to open your project in VSCode.
Open VSCode and choose Open Folder → Select your project folder (SearchConsole)
If you get a prompt to install extensions, go ahead and choose Yes
Open a Terminal from VSCode by choosing Terminal → New Terminal
Test that everything is working by running your app
dotnet run
All right!
Let’s proceed with installing Bionic Search
2) Add Microsoft.Extensions.Logging.Abstractions as NuGet
Add a NuGet package manager to VSCode. We recommend this one:
Name: NuGet Package Manager Id: jmrog.vscode-nuget-package-manager VS Marketplace Link: https://marketplace.visualstudio.com/items?itemName=jmrog.vscode-nuget-package-manager
Before installing the package, make sure you are working in the directory of your C# project.
- Open the command pallette (Shift-CTRL/CMD-P) and type “nuget”.
- Choose NuGet Package Manager: Add Package and search for Microsoft.Extensions.Logging.Abstractions.
- Choose the latest stable version (number 6.0.0 or higher).
3) Include BionicSearchLib as assembly reference
Place your BionicSearchLib.dll file in your project directory
In VSCode, open your .csproj file (SearchConsole.csproj)
Add a new ItemGroup with a reference to the dll just before the </Project> tag
<ItemGroup>
<Reference Include="BionicSearchLib">
<HintPath>BionicSearchLib.dll</HintPath>
</Reference>
</ItemGroup>
4) Prepare your app
Go back to Program.cs → Remove the default “Hello, World!” lines from your app.
To get started we’ll need a simple structure with a using and a namespace argument
using BionicSearchLib;
namespace SearchConsole
{
internal class Program
{
private static void Main()
{
//write your code here
}
}
}
Then we’ll go on to add Bionic.
5) Create an instance of BionicSearchEngine
Inside your Main() function add the following code snippet. In this example we do not need the logger functions, so we’ll add null statements. Also, we will use configuration number 103.
var SearchEngine = new BionicSearchEngine(null, null, 103);
6) Prepare and add your data
Add your airports.txt file to the root folder of your project
The airports.txt file contains 40.000+ lines with airports including information about regions and countries. We will divide it into a string per line, and then add it to an array in our app.
Reference the data file in the code. Continue inside your Main() function.
//
// Prepare data
//
string fileName = "airports.txt";
string path = Path.Combine(Environment.CurrentDirectory, @"../..", fileName);
var lines = File.ReadAllLines(path);
7) Insert data into a list with the Document class
To index the data we will add the strings from our lines to our Document class. This class also takes arguments like a key, segment number, and some extra metadata for the client. We will not use these in this simple example.
Insert by looping through the lines we read from airports.txt. Add key 0,1,2 .. and up to the entries.
Lastly, run Insert on our instance of the engine with our documents as an array.
//
// Insert
//
var key = 0; // foreign key
var documents = new List<Document>();
foreach (var item in lines)
{
var doc = new Document(key, 0, item, "");
documents.Add(doc);
key++;
}
SearchEngine.Insert(documents.ToArray());
8) Index the documents and check status with a progress bar
Index by simply running
SearchEngine.IndexAsync();
And check for status by running the status function. We will do this with a console log to create a progress loader when indexing.
var status = SearchEngine.Status;
while (!status.SearchIsAllowed) // Check and print status while indexing
{
Console.WriteLine(status.IndexProgressPercent);
System.Threading.Thread.Sleep(5); // log every 5ms
}
This prints out the index progress as percentage in the console:
9) Create a search query
The SearchQuery class takes a number of arguments. To create a structure for this, we will add variables with explanations.
In this example we will search for Frankfurt airport. We will use the Bionic RelevancyRanking algorithm, which is the best algorithms for most use cases. We will not use logger functions so this will be an empty string.
Feel free to search for another airport.
var text = "frankfrt"; // pattern to be searched for
var algorithm = Algorithm.ProprietaryRelevancyRanking; // Default algorithm
var numRecords = 10; // Records to be returned
var timeOutLimit = 1000; // Timeout if cpu overload in milliseconds
var rmDuplicates = true; // remove duplicates with same key
var logPrefix = ""; // logger prefix per search
var query = new SearchQuery(text, algorithm, numRecords, timeOutLimit, rmDuplicates, logPrefix);
10) Reading our search results
The Search function answers with an array of SearchRecords.
Loop through the records to display them. The class has multiple properties, but we are mostly interested in the DocumentTextToBeIndexed as it displays the text of the result.
var result = SearchEngine.Search(query);
for (int i = 0; i < result.SearchRecords.Length; i++)
{
Console.WriteLine(result.SearchRecords[i].DocumentTextToBeIndexed);
}
Run your app with “dotnet run” to display your results
That’s it! You have now built an app with Bionic Search 🎉
11) (Optional) Filtering out results with a low score
By default, the pattern recognition of the Search function will almost always answer with results, even if the metric score is very low.
The Bionic Search Engine uses pattern recognition on the whole search string, and not just single words.
Read about the Core principles to learn more.
If you want to filter out low-ranking results, we can use the MetricScore property of SearchRecords.
One way to do this is to create an if state that only displays results if the score is higher than a set threshold.
var result = SearchEngine.Search(query);
for (int i = 0; i < result.SearchRecords.Length; i++)
{
if(result.SearchRecords[i].MetricScore >= 100)
{
Console.WriteLine(result.SearchRecords[i].DocumentTextToBeIndexed);
Console.WriteLine(result.SearchRecords[i].MetricScore);
}
}