Skip to content
This repository has been archived by the owner on Jul 2, 2024. It is now read-only.

Getting Started

Brad Wilson edited this page Mar 17, 2014 · 1 revision

ElasticLINQ is an implementation of the LINQ Query Provider that allows developers to search their Elasticsearch object store and return the resulting documents as CLR classes. This leverages the developer's experience with LINQ and relational data stores, and eases the transition into distributed NoSQL data stores.

How do I use ElasticLINQ?

As with most open source libraries for .NET, ElasticLINQ binaries are available via NuGet. Just install the package ElasticLINQ into your project. Currently, we support Desktop .NET 4.5 and later.

To get started, you will need an Elasticsearch server (or server cluster). It can be installed on both Windows and Linux, with installation instructions found here. The Elasticsearch API is done via HTTP and JSON, so you will need to be able to have HTTP access to the server (on port 9200, with a default installation).

Elasticsearch segregates data into what's called an index (think of this as a database in a traditional data world). When searching Elasticsearch, you can narrow your search to one or more indices, or you can search all the indices in the server cluster.

Connection and Context

To start, you will need to create the connection object which instructs ElasticLINQ how to connect to the server:

var connection = new ElasticConnection(new Uri("http://myserver:9200"));

There are four additional optional constructor arguments: username and password for servers that require authentication, a timeout value to tell Elasticsearch how long you're willing to wait for an answer, and an index parameter to tell Elasticsearch which index to search (to search multiple indices, pass a comma-separated string like "index1,index2").

Once you have the connection object, you'll need to create the context object; this object is where your queries will start.

var context = new ElasticContext(connection);

This constructor, too, has optional arguments: a mapping object which controls query generation options, a retryPolicy object which allows you to specify retry logic for failed searchs, and a log object that lets you integrate ElasticLINQ's logging into your existing logging solution.

Querying with the Context

The context object's Query<T> method starts a query against a particular document type in Elasticsearch, and returns an IQueryable<T>.

IQueryable<Person> query = context.Query<Person>();

From here, you can use many of the traditional LINQ operations which will be translated into an Elasticsearch request.

As of version 1.0, the following LINQ operations are supported: Where, Skip, Take, Select, OrderBy and OrderByDescending, ThenBy and ThenByDescending, First and FirstOrDefault, and Single and SingleOrDefault.

As with any LINQ implementation, there are limitations on the types of queries that are supported, since your C# code must be translate into an appropriate query at runtime. The Where operation supports most common expressions, including: ==, !=, <, <=, >, >=, ||, and &&; as well as Equals and Contains.

Full-text searching

Elasticsearch offers a full text search feature called query_string. It's intended to take user input (which means searches are case-insensitive), and lets the user specify things like wildcards and join operators like AND and OR. To issue a query_string search, use the QueryString extension method on your IQueryable<T>:

query.QueryString("this AND that OR the other thing")

For more information on full-text searching with query_string, see the Elasticsearch documentation.

Custom queries with ElasticMethods

In addition to the built-in LINQ operations, ElasticLINQ also supports four custom operations implemented as static methods on the ElasticMethods class: Regexp, Prefix, ContainsAny, and ContainsAll. The first two are fairly self explanatory; the latter two require a bit of background.

Since LINQ (and relational databases) really don't support the notion of columns which are themselves collections, there is no existing syntax that adequately expresses the idea of matching collections against collections. The Contains method will do the one-to-many mapping, and is supported in both directions with ElasticLINQ as you'll see below. When you have a collection field, and you want to see if it matches any (or all) of the values in a list, you can use ElasticMethods.ContainsAny or ElasticMethods.ContainsAll to express that style of query.

Here are the four types of collection-related queries:

var names = new[] { "Brad", "Jim", "Damien" };
 
// See if a field matches one of many values
query.Where(x => names.Contains(x.Name))
 
// See if a collection field contains a single value
query.Where(x => x.Aliases.Contains("Brad"))
 
// See if a collection field contains any value from a list
query.Where(x => ElasticMethods.ContainsAny(x.Aliases, names))
 
// See if a collection field contains all values from a list
query.Where(x => ElasticMethods.ContainsAll(x.Aliases, names))

Custom queries and projections with ElasticFields

When querying (with Where and Query) and projecting (with Select), you have access to two pieces of metadata from Elasticsearch: the document ID, and the search score. These fields are available as static properties named ElasticFields.Id and ElasticFields.Score, respectively.

A note about scoring: in Elasticsearch (and Lucene), a search is performed in two stages: a query, which scores the results of the search, and a filter, which further filters the result of the query. The default query and filter return all documents, so you can query without a filter, filter without a query, or provide neither (and simply get all the documents in Elasticsearch).

When you use Where in ElasticLINQ, that translates into a filter. We chose this by default because it is significantly faster than a query, and the results of filter are cacheable by Elasticsearch. If you don't intend to use scoring, then filter is the way to go. If you want to issue a query so you can get scoring (for example, because you're doing full-text style searching), you can use the Query extension method that we've added to IQueryable; it has the same syntax and usage as Where, except that it results in a query for your search. You can mix both Query and Where in the same request, but be aware that the two-stage system in Elasticsearch means that all Query criteria will be searched before any Where criteria are.