C# 如何使用 Elasticsearch (ES)

 

Elasticsearch简介

 

Elasticsearch (ES)是一个基于Apache Lucene(TM)的开源搜索引擎,无论在开源还是专有领域,Lucene可以被认为是迄今为止最先进、性能最好的、功能最全的搜索引擎库。 

 

但是,Lucene只是一个库。想要发挥其强大的作用,你需使用C#将其集成到你的应用中。Lucene非常复杂,你需要深入的了解检索相关知识来理解它是如何工作的。 

 

Elasticsearch是使用Java编写并使用Lucene来建立索引并实现搜索功能,但是它的目的是通过简单连贯的RESTful API让全文搜索变得简单并隐藏Lucene的复杂性。 

 

不过,Elasticsearch不仅仅是Lucene和全文搜索引擎,它还提供:

 

  • 分布式的实时文件存储,每个字段都被索引并可被搜索

     

  • 实时分析的分布式搜索引擎

     

  • 可以扩展到上百台服务器,处理PB级结构化或非结构化数据

 

而且,所有的这些功能被集成到一台服务器,你的应用可以通过简单的RESTful API、各种语言的客户端甚至命令行与之交互。

 

上手Elasticsearch非常简单,它提供了许多合理的缺省值,并对初学者隐藏了复杂的搜索引擎理论。它开箱即用(安装即可使用),只需很少的学习既可在生产环境中使用。Elasticsearch在Apache 2 license下许可使用,可以免费下载、使用和修改。 

 

随着知识的积累,你可以根据不同的问题领域定制Elasticsearch的高级特性,这一切都是可配置的,并且配置非常灵活。

 

以上内容来自 [百度百科] 

 

关于ES详细概念见:

 

http://88250.b3log.org/full-text-search-elasticsearch#b3_solo_h3_0

 

使用C#操作ES

 

NEST是一个高层的客户端,可以映射所有请求和响应对象,拥有一个强类型查询DSL(领域特定语言),并且可以使用.net的特性比如协变、Auto Mapping Of POCOs,NEST内部使用的依然是Elasticsearch.Net客户端。

 

Elasticsearch.net(NEST)客户端提供了强类型查询DSL,方便用户使用,源码下载。(https://github.com/elastic/elasticsearch-net/releases/tag/2.4.4)

 

一、如何安装NEST

 

打开VS的工具菜单,通过NuGet包管理器控制台,输入以下命令安装NEST

 

Install-Package NEST

 

安装后引用了以下三个DLL

 

  • Elasticsearch.Net.dll(2.4.4)

     

  • Nest.dll(2.4.4)

     

  • Newtonsoft.Json.dll(9.0版本)

 

二、链接elasticsearch

 

你可以通过单个节点或者指定多个节点使用连接池链接到Elasticsearch集群,使用连接池要比单个节点链接到Elasticsearch更有优势,比如支持负载均衡、故障转移等。

 

通过单点链接:

 

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

var settings = new ConnectionSettings(node);

var client = new ElasticClient(settings);

 

通过连接池链接:

 

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 ElasticClient(settings);

 

NEST Index

 

为了知道请求需要操作哪个索引,Elasticsearch API期望收到一个或多个索引名称作为请求的一部分。

 

一、指定索引

 

1、可以通过ConnectionSettings使用.DefaultIndex(),来指定默认索引。当一个请求里没有指定具体索引时,NEST将请求默认索引。

 

var settings = new ConnectionSettings()

    .DefaultIndex("defaultindex");

 

2、可以通过ConnectionSettings使用.MapDefaultTypeIndices(),来指定被映射为CLR类型的索引。

 

var settings = new ConnectionSettings()

    .MapDefaultTypeIndices(m => m

        .Add(typeof(Project), "projects")

    );

 

注意:通过.MapDefaultTypeIndices()指定索引的优先级要高于通过.DefaultIndex()指定索引,并且更适合简单对象(POCO)

 

3、另外还可以显示的为请求指定索引名称,例如:

 

var response = client.Index(student, s=>s.Index("db_test"));

var result = client.Search<Student>(s => s.Index("db_test"));

var result = client.Delete<Student>(null, s => s.Index("db_test"));

……

 

注意:当现实的为请求指定索引名称时,这个优先级是最高的,高于以上两种方式指定的索引。

 

4、一些Elasticsearch API(比如query)可以采用一个、多个索引名称或者使用_all特殊标志发送请求,请求NEST上的多个或者所有节点

 

//请求单一节点

var singleString = Nest.Indices.Index("db_studnet");

var singleTyped = Nest.Indices.Index<Student>();

 

ISearchRequest singleStringRequest = new SearchDescriptor<Student>().Index(singleString);

ISearchRequest singleTypedRequest = new SearchDescriptor<Student>().Index(singleTyped);

 

//请求多个节点

var manyStrings = Nest.Indices.Index("db_studnet", "db_other_student");

var manyTypes = Nest.Indices.Index<Student>().And<OtherStudent>();

 

ISearchRequest manyStringRequest = new SearchDescriptor<Student>().Index(manyStrings);

ISearchRequest manyTypedRequest = new SearchDescriptor<Student>().Index(manyTypes);

 

//请求所有节点

var indicesAll = Nest.Indices.All;

var allIndices = Nest.Indices.AllIndices;

 

ISearchRequest indicesAllRequest = new SearchDescriptor<Student>().Index(indicesAll);

ISearchRequest allIndicesRequest = new SearchDescriptor<Student>().Index(allIndices);

 

二、创建索引

 

Elasticsearch API允许你创建索引的同时对索引进行配置,例如:

 

var descriptor = new CreateIndexDescriptor("db_student")

    .Settings(s => s.NumberOfShards(5).NumberOfReplicas(1));

client.CreateIndex(descriptor);

 

这里指定了该索引的分片数为5、副本数为1。

 

三、删除索引

 

Elasticsearch API允许你删除索引,例如:

 

var descriptor = new DeleteIndexDescriptor("db_student").Index("db_student");

client.DeleteIndex(descriptor)

 

这里制定了要删除的索引名称“db_student”,以下为更多删除用例:

 

 //删除指定索引所在节点下的所有索引

 var descriptor = new DeleteIndexDescriptor("db_student").AllIndices();

 

NEST Mapping

 

NEST提供了多种映射方法,这里介绍下通过Attribute自定义映射。

 

一、简单实现

 

1、定义业务需要的POCO,并指定需要的Attribute

 

[ElasticsearchType(Name = "student")]

public class Student

{

    [Nest.String(Index = FieldIndexOption.NotAnalyzed)]

    public string Id { get; set; }

    [Nest.String(Analyzer = "standard")]

    public string Name { get; set; }

    [Nest.String(Analyzer = "standard")]

    public string Description { get; set; }

    public DateTime DateTime { get; set; }

}

 

2、接着我们通过.AutoMap()来实现映射

 

var descriptor = new CreateIndexDescriptor("db_student")

    .Settings(s => s.NumberOfShards(5).NumberOfReplicas(1))

    .Mappings(ms => ms

        .Map<Student>(m => m.AutoMap())

    );

client.CreateIndex(descriptor);

 

注意:通过.Properties()可以重写通过Attribute定义的映射

 

二、Attribute介绍

 

1、StringAttribute

 

 

2、NumberAttribute

 

 

3、BooleanAttribute

 

属性名值类型描述
Boost double 加权值,值越大得分越高
NullValue double 插入文档时,如果数据为NULL时的默认值

 

4、DateAttribute

 

属性名值类型描述
Boost double 加权值,值越大得分越高
NullValue string 插入文档时,如果数据为NULL时的默认值
Format string  

 

5、ObjectAttribute

 

属性名值类型描述
type string/Type 构造函数参数,指定当前属性的类型T
Dynamic DynamicMapping  

 

NEST Search

 

NEST提供了支持Lambda链式query DLS(领域特定语言)方式,以下是简单实现及各个query的简述。

 

一、简单实现

 

1、定义SearchDescriptor,方便项目中复杂业务的实现

 

var query = new Nest.SearchDescriptor<Models.ESObject>();

var result = client.Search<Student>(x => query)

 

2、检索title和content中包含key,并且作者不等于“wenli”的文档

 

query.Query(q =>

    q.Bool(b =>

        b.Must(m =>

            m.MultiMatch(t => t.Fields(f => f.Field(obj => obj.Title).Field(obj => obj.Content)).Query(key))

        )

        .MustNot(m =>

            m.QueryString(t => t.Fields(f => f.Field(obj => obj.Author)).Query("wenli"))

        )

    )

);

 

注意:

 

如果Elasticsearch使用默认分词,Title和Content的attribute为[Nest.String(Analyzer = "standard")]

 

如果Elasticsearch使用的是IK分词,Title和Content的attribute为[Nest.String(Analyzer = "ikmaxword")]或者[Nest.String(Analyzer = "ik_smart")]

 

Author的attribute为[Nest.String(Index = FieldIndexOption.NotAnalyzed)],禁止使用分析器

 

3、过滤作者等于“wenli”的文档

 

query.PostFilter(x => x.Term(t => t.Field(obj => obj.Author).Value("wenli")));

 

4、过滤作者等于“wenli”或者等于“yswenli”的文档,匹配多个作者中间用空格隔开

 

query.PostFilter(x => x.QueryString(t => t.Fields(f => f.Field(obj => obj.Author)).Query("wenli yswenli")));

 

5、过滤数量在1~100之间的文档

 

query.PostFilter(x => x.Range(t => t.Field(obj => obj.Number).GreaterThanOrEquals(1).LessThanOrEquals(100)));

 

6、排序,按照得分倒叙排列

 

query.Sort(x => x.Field("_score", Nest.SortOrder.Descending));

 

7、定义高亮样式及字段

 

query.Highlight(h => h

    .PreTags("<b>")

    .PostTags("</b>")

    .Fields(

        f => f.Field(obj => obj.Title),

        f => f.Field(obj => obj.Content),

        f => f.Field("_all")

    )

);

 

8、拼装查询内容,整理数据,方便前段调用

 

var list = result.Hits.Select(c => new Models.ESObject()

{

    Id = c.Source.Id,

    Title = c.Highlights == null ? c.Source.Title : c.Highlights.Keys.Contains("title") ? string.Join("", c.Highlights["title"].Highlights) : c.Source.Title, //高亮显示的内容,一条记录中出现了几次

    Content = c.Highlights == null ? c.Source.Content : c.Highlights.Keys.Contains("content") ? string.Join("", c.Highlights["content"].Highlights) : c.Source.Content, //高亮显示的内容,一条记录中出现了几次

    Author = c.Source.Author,

    Number = c.Source.Number,

    IsDisplay = c.Source.IsDisplay,

    Tags = c.Source.Tags,

    Comments = c.Source.Comments,

    DateTime = c.Source.DateTime,

})

 

二、query DSL介绍 

 

elasticsearch.net Document

 

文档操作包含添加/更新文档、局部更新文档、删除文档及对应的批量操作文档方法。

 

一、添加/更新文档及批量操作

 

添加/更新单一文档

 

Client.Index(student);

 

批量添加/更新文档

 

var list = new List<Student>();

client.IndexMany<Student>(list);

 

二、局部更新单一文档及批量操作

 

局部更新单一文档

 

client.Update<Student, object>("002", upt => upt.Doc(new { Name = "wenli" }));

 

局部更新批量文档

 

var ids = new List<string>() { "002" };

var bulkQuest = new BulkRequest() { Operations = new List<IBulkOperation>() };

foreach (var v in ids)

{

    var operation = new BulkUpdateOperation<Student, object>(v);

    operation.Doc = new { Name = "wenli" };

    bulkQuest.Operations.Add(operation);

}

var result = client.Bulk(bulkQuest);

 

三、删除文档及批量操作

 

删除单一文档

 

client.Delete<Student>("001");

 

批量删除文档

 

var ids = new List<string>() { "001", "002" };

var bulkQuest = new BulkRequest() { Operations = new List<IBulkOperation>() };

foreach (var v in ids)

{

    bulkQuest.Operations.Add(new BulkDeleteOperation<Student>(v));

}

var result = client.Bulk(bulkQuest);

 

转至: cnblogs.com/yswenli/p/6266569.html

posted @ 2017-07-27 13:49  领悟.海洋  阅读(19482)  评论(5编辑  收藏  举报