Getting started with the high-level .NET client (Lucenia.Client)
Preview
Lucenia.Client is a high-level .NET client. It provides strongly typed requests and responses as well as Query DSL. It frees you from constructing raw JSON requests and parsing raw JSON responses by providing models that parse and serialize/deserialize requests and responses automatically. Lucenia.Client also exposes the Lucenia.Net low-level client if you need it. For the client’s complete API documentation, see the Lucenia.Client API documentation (COMING SOON).
This getting started guide illustrates how to connect to Lucenia, index documents, and run queries.
Installing Lucenia.Client
To install Lucenia.Client, download the Lucenia.Client NuGet package (COMING SOON) and add it to your project in an IDE of your choice. In Microsoft Visual Studio, follow the steps below:
- In the Solution Explorer panel, right-click on your solution or project and select Manage NuGet Packages for Solution.
- Search for the Lucenia.Client NuGet package, and select Install.
Alternatively, you can add Lucenia.Client to your .csproj file:
<Project>
...
<ItemGroup>
<PackageReference Include="Lucenia.Client" Version="0.1.0" />
</ItemGroup>
</Project>
Example
The following example illustrates connecting to Lucenia, indexing documents, and sending queries on the data. It uses the Student class to represent one student, which is equivalent to one document in the index.
public class Student
{
public int Id { get; init; }
public string FirstName { get; init; }
public string LastName { get; init; }
public int GradYear { get; init; }
public double Gpa { get; init; }
}
By default, Lucenia.Client uses camel case to convert property names to field names.
Connecting to Lucenia
Use the default constructor when creating an LuceniaClient object to connect to the default Lucenia host (http://localhost:9200
).
var client = new LuceniaClient();
To connect to your Lucenia cluster through a single node with a known address, specify this address when creating an instance of Lucenia.Client:
var nodeAddress = new Uri("http://myserver:9200");
var client = new LuceniaClient(nodeAddress);
You can also connect to Lucenia through multiple nodes. Connecting to your Lucenia cluster with a node pool provides advantages like load balancing and cluster failover support. To connect to your Lucenia cluster using multiple nodes, specify their addresses and create a ConnectionSettings
object for the Lucenia.Client instance:
var nodes = new Uri[]
{
new Uri("http://myserver1:9200"),
new Uri("http://myserver2:9200"),
new Uri("http://myserver3:9200")
};
var pool = new StaticConnectionPool(nodes);
var settings = new ConnectionSettings(pool);
var client = new LuceniaClient(settings);
Using ConnectionSettings
ConnectionConfiguration
is used to pass configuration options to the low-level Lucenia.Net client. ConnectionSettings
inherits from ConnectionConfiguration
and provides additional configuration options. To set the address of the node and the default index name for requests that don’t specify the index name, create a ConnectionSettings
object:
var node = new Uri("http://myserver:9200");
var config = new ConnectionSettings(node).DefaultIndex("students");
var client = new LuceniaClient(config);
Indexing one document
Create one instance of Student:
var student = new Student { Id = 100, FirstName = "Paulo", LastName = "Santos", Gpa = 3.93, GradYear = 2021 };
To index one document, you can use either fluent lambda syntax or object initializer syntax.
Index this Student into the students
index using fluent lambda syntax:
var response = client.Index(student, i => i.Index("students"));
Index this Student into the students
index using object initializer syntax:
var response = client.Index(new IndexRequest<Student>(student, "students"));
Indexing many documents
You can index many documents from a collection at the same time by using the Lucenia.Client’s IndexMany
method:
var studentArray = new Student[]
{
new() {Id = 200, FirstName = "Shirley", LastName = "Rodriguez", Gpa = 3.91, GradYear = 2019},
new() {Id = 300, FirstName = "Nikki", LastName = "Wolf", Gpa = 3.87, GradYear = 2020}
};
var manyResponse = client.IndexMany(studentArray, "students");
Searching for a document
To search for a student indexed above, you want to construct a query that is analogous to the following Query DSL query:
GET students/_search
{
"query" : {
"match": {
"lastName": "Santos"
}
}
}
The query above is a shorthand version of the following explicit query:
GET students/_search
{
"query" : {
"match": {
"lastName": {
"query": "Santos"
}
}
}
}
In Lucenia.Client, this query looks like this:
var searchResponse = client.Search<Student>(s => s
.Index("students")
.Query(q => q
.Match(m => m
.Field(fld => fld.LastName)
.Query("Santos"))));
You can print out the results by accessing the documents in the response:
if (searchResponse.IsValid)
{
foreach (var s in searchResponse.Documents)
{
Console.WriteLine($"{s.Id} {s.LastName} {s.FirstName} {s.Gpa} {s.GradYear}");
}
}
The response contains one document, which corresponds to the correct student:
100 Santos Paulo 3.93 2021
Using Lucenia.Client methods asynchronously
For applications that require asynchronous code, all method calls in Lucenia.Client have asynchronous counterparts:
// synchronous method
var response = client.Index(student, i => i.Index("students"));
// asynchronous method
var response = await client.IndexAsync(student, i => i.Index("students"));
Falling back on the low-level Lucenia.Net client
Lucenia.Client exposes the low-level the Lucenia.Net client you can use if anything is missing:
var lowLevelClient = client.LowLevel;
var searchResponseLow = lowLevelClient.Search<SearchResponse<Student>>("students",
PostData.Serializable(
new
{
query = new
{
match = new
{
lastName = new
{
query = "Santos"
}
}
}
}));
if (searchResponseLow.IsValid)
{
foreach (var s in searchResponseLow.Documents)
{
Console.WriteLine($"{s.Id} {s.LastName} {s.FirstName} {s.Gpa} {s.GradYear}");
}
}
Sample program
The following is a complete sample program that illustrates all of the concepts described above. It uses the Student class defined above.
using Lucenia.Client;
using Lucenia.Net;
namespace NetClientProgram;
internal class Program
{
private static ILuceniaClient osClient = new LuceniaClient();
public static void Main(string[] args)
{
Console.WriteLine("Indexing one student......");
var student = new Student { Id = 100,
FirstName = "Paulo",
LastName = "Santos",
Gpa = 3.93,
GradYear = 2021 };
var response = osClient.Index(student, i => i.Index("students"));
Console.WriteLine(response.IsValid ? "Response received" : "Error");
Console.WriteLine("Searching for one student......");
SearchForOneStudent();
Console.WriteLine("Searching using low-level client......");
SearchLowLevel();
Console.WriteLine("Indexing an array of Student objects......");
var studentArray = new Student[]
{
new() { Id = 200,
FirstName = "Shirley",
LastName = "Rodriguez",
Gpa = 3.91,
GradYear = 2019},
new() { Id = 300,
FirstName = "Nikki",
LastName = "Wolf",
Gpa = 3.87,
GradYear = 2020}
};
var manyResponse = osClient.IndexMany(studentArray, "students");
Console.WriteLine(manyResponse.IsValid ? "Response received" : "Error");
}
private static void SearchForOneStudent()
{
var searchResponse = osClient.Search<Student>(s => s
.Index("students")
.Query(q => q
.Match(m => m
.Field(fld => fld.LastName)
.Query("Santos"))));
PrintResponse(searchResponse);
}
private static void SearchForAllStudentsWithANonEmptyLastName()
{
var searchResponse = osClient.Search<Student>(s => s
.Index("students")
.Query(q => q
.Bool(b => b
.Must(m => m.Exists(fld => fld.LastName))
.MustNot(m => m.Term(t => t.Verbatim().Field(fld => fld.LastName).Value(string.Empty)))
)));
PrintResponse(searchResponse);
}
private static void SearchLowLevel()
{
// Search for the student using the low-level client
var lowLevelClient = osClient.LowLevel;
var searchResponseLow = lowLevelClient.Search<SearchResponse<Student>>
("students",
PostData.Serializable(
new
{
query = new
{
match = new
{
lastName = new
{
query = "Santos"
}
}
}
}));
PrintResponse(searchResponseLow);
}
private static void PrintResponse(ISearchResponse<Student> response)
{
if (response.IsValid)
{
foreach (var s in response.Documents)
{
Console.WriteLine($"{s.Id} {s.LastName} " +
$"{s.FirstName} {s.Gpa} {s.GradYear}");
}
}
else
{
Console.WriteLine("Student not found.");
}
}
}