Link Search Menu Expand Document Documentation Menu

Getting started with the high-level .NET client (SmartObserve.Client)

SmartObserve.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. SmartObserve.Client also exposes the SmartObserve.Net low-level client if you need it. For the client’s complete API documentation, see the SmartObserve.Client API documentation.

This getting started guide illustrates how to connect to SmartObserve, index documents, and run queries. For the client source code, see the smartobserve-net repo.

Installing SmartObserve.Client

To install SmartObserve.Client, download the SmartObserve.Client NuGet package 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 SmartObserve.Client NuGet package, and select Install.

Alternatively, you can add SmartObserve.Client to your .csproj file:

<Project>
  ...
  <ItemGroup>
    <PackageReference Include="SmartObserve.Client" Version="1.0.0" />
  </ItemGroup>
</Project>

Example

The following example illustrates connecting to SmartObserve, 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, SmartObserve.Client uses camel case to convert property names to field names.

Connecting to SmartObserve

Use the default constructor when creating an SmartObserveClient object to connect to the default SmartObserve host (http://localhost:9200).

var client  = new SmartObserveClient();

To connect to your SmartObserve cluster through a single node with a known address, specify this address when creating an instance of SmartObserve.Client:

var nodeAddress = new Uri("http://myserver:9200");
var client = new SmartObserveClient(nodeAddress);

You can also connect to SmartObserve through multiple nodes. Connecting to your SmartObserve cluster with a node pool provides advantages like load balancing and cluster failover support. To connect to your SmartObserve cluster using multiple nodes, specify their addresses and create a ConnectionSettings object for the SmartObserve.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 SmartObserveClient(settings);

Using ConnectionSettings

ConnectionConfiguration is used to pass configuration options to the low-level SmartObserve.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 SmartObserveClient(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 SmartObserve.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 SmartObserve.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 SmartObserve.Client methods asynchronously

For applications that require asynchronous code, all method calls in SmartObserve.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 SmartObserve.Net client

SmartObserve.Client exposes the low-level the SmartObserve.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 SmartObserve.Client;
using SmartObserve.Net;

namespace NetClientProgram;

internal class Program
{
    private static ISmartObserveClient osClient = new SmartObserveClient();

    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.");
        }
    }
}