1. 什么是ElasticSearch?

ElasticSearch is a powerful open source search and analytics engine that makes data easy to explore.

可以简单理解成索引加检索的工具,当然它功能多于此。
ElasticSearch分为服务端与客户端,服务端提供REST API,客户端使用REST API。

2.怎么安装Elastic?

  1. 安装JDK( 下载地址)
  2. 安装ElasticSearch( 下载地址)
    1. 解压,运行\bin\elasticsearch.bat.
    2. 浏览器输入http://localhost:9200/,可以看到如图:

    3. 安装成功。
  3. 安装ElasticSearch – header plugin  https://github.com/mobz/elasticsearch-head

    文档中有详细说明

    完成后,在如下图的地方找到一个html

  4. 安装完成~

3. 如何使用NEST客户端(文档:http://nest.azurewebsites.net/nest/quick-start.html)

  1. 连接
    1. var node = new Uri("http://localhost:9200/");
    2. var settings = new ConnectionSettings(
    3. node,
    4. defaultIndex: " geopoint-tests "
    5. );
    6. var client = new ElasticClient(settings);
  2. 添加索引
    1. client.CreateIndex("geopoint-tests");

    上面这句代码是可以不用写的,因为在调用下面的index方法的时候,如果没有指定使用哪个index,ElasticSearch会直接使用我们在setting中的defaultIndex,如果没有,则会自动创建。

    1. client.Index(obj);

    但是如何你需要使用Mapping来调整索引结构,就会需要CreateIndex这个方法。具体的会在下面的Mapping中提到

  3. 添加数据
    1. client.Index(obj)
  4. 搜索

    正常来说,搜索的需求一般是我们传入一个keyword(和需要搜索的field name),返回符合条件的列表,那么搜索就分为全文搜索和单属性搜索。顾名思义,全文搜索就是用keyword去匹配所有的属性,单属性搜索就是只匹配指定的属性。

  • 全文搜索:
    1. keyword = String.Format("*{0}*", keyword);
      1. //默认的Operator是Or,当keyword是类似于"One Two"之类的中间有空格的时候,会被当成两个关键词搜索,然后搜索结果进行or运算
      2. //所以我们需要根据需求来调整Operator
    2. var searchResults = client.Search<T>(s => s
    3. .Index(index)
    4. .Query(q => q.QueryString(qs => qs.Query(keyword).DefaultOperator(Operator.And)))
    5. );
    6. return searchResults.Documents;

另外由于ES是分词搜索,所以当我们要用"One"来搜索完整的单词"JustOne"的时候,就必须在"One"外面添加**,类似于SQL里面的%keyword%,但是这样的做法会导致在用完整的单词来搜索的时候搜索不到结果,所以我们需要使用下面的方式(如果有更好的方法请不吝赐教):

  1. wholeKeyword = keyword;
  2. keyword = String.Format("*{0}*", keyword);
  3. QueryContainer query = new QueryStringQuery() { Query = keyword, DefaultOperator = Operator.And };
  4. if(!String.IsNullOrEmpty(wholeKeyword)){
  5. QueryContainer wholeWordQuery = new QueryStringQuery() { Query = wholeKeyword };
  6. query = query || wholeWordQuery;
  7. }
  8. var searchResults = client.Search<Person>(s => s
  9. .Index("zhixiao-application")
  10. .Query(query)
  11. );
  • 指定属性搜索

    指定属性的搜索有两种:

  1. 使用term Query
QueryContainer query2 = new TermQuery { Field = item.Key, Value = item.Value.ToLower() };

Term是一个被索引的精确值,也就是说Foo, foo, FOO是不相等的,因此

在使用term query的时候要注意,term query在搜索的Field已经被索引的时候,是不支持大写的。下面为elasticSearch - header测试

所有数据:

大写搜索:

小写搜索:

NEST的使用:

  1. var searchResults = client.Search<Person>(s => s
  2. .Index("zhixiao-application")
  3. .Query(q => q.Term(t => t.OnField(f => f.Lastname == "keyword")))
  4. );

    或者(效果一样):

  5. QueryContainer termQuery = new TermQuery { Field = "lastname", Value = "keyword" };
  6. var searchResults = client.Search<Person>(s => s
  7. .Index("zhixiao-application")
  8. .Query(termQuery)
  9. );

PS:term query的Field是必须的,如果Field为空,会产生下面的错误           

2.使用 Query String query

QueryString query一般用于全文搜索,但是也可以用于单个属性的搜索(设置DefaultField属性),queryString query可以不区分大小写。QueryString还有一个好处就是我们可以搜索一个term中的一部分,例如lastname为"t Boterhuis 1",那么我们可以用"terhuis"搜索到这个数据(虽然需要在外面包上**),在term query里面就做不到,因为ES把每一个属性的值都分析成一个个单独的term,提高了搜索的效率。

下面为elasticSearch - header测试:

完整term搜索(大写):

完整term搜索(小写):

部分搜索(大写,不带**):

部分搜索(大写,带**):

部分搜索(小写,带**):

多词语搜索:当我们想搜索类似于:"t Boterhuis 2"这样的多个单词构成的keyword(用空格分开),term query是无法查询的,term query顾名思义就是单词查询。不能支持多单词查询

QueryString query:

大家可以看到,第三条也被搜索进来了,这是因为ES把"t Boterhuis 2"解析成了三个词汇"t"" Boterhuis""2"。然后分开搜索,把结果集合并,所以ID为4的记录也被搜索出来了。那么我们如何让合起来搜索呢?

  1. string keyword = "t Boterhuis 2";
  2. QueryContainer wholeWordQuery = new QueryStringQuery() { Query = keyword, DefaultOperator = Operator.And };
  3. var searchResults = client.Search<Person>(s => s
  4. .Index("zhixiao-application")
  5. .Query(wholeWordQuery)
  6. );

QueryString query有一个DefaultOperator的属性,我们可以将其设置为And,这样搜索的时候,ES会将几个term的search结果做and运算。

但是有一个比较大的问题是如果我的keyword是"Aberdeen Boterhuis",

这样也可以搜索出结果来:

我们搜索出了ID为7的数据,因为这条数据firstname里面有Aberdeen ,last name里面有Boterhuis。

目前还没有找到比较好的方法来解决这个问题,如果各位有好的方法请不吝赐教。

5.排序

搜索需要我们重新构建索引,这样才能发现错误并且解决他们。

首先我们把原先的索引先删除了

  1. var response = client.DeleteIndex(new DeleteIndexRequest(new IndexNameMarker() { Name = "zhixiao-application", Type = typeof(Person) };

然后重新创建索引

  1. var indexResult = client.CreateIndex("zhixiao- application");
  2. var response1 = client.Map<Person>(m => m.MapFromAttributes());
  3. IEnumerable<Person> persons = new List<Person>
  4. {
  5. new Person()
  6. {
  7. Id = "4",
  8. Firstname = "Boterhuis-040",
  9. Lastname = "Gusto-040",
  10. Chains = new string[]{ "a","b","c" },
  11. },
  12. new Person()
  13. {
  14. Id = "5",
  15. Firstname = "sales@historichousehotels.com",
  16. Lastname = "t Boterhuis 1",
  17. Chains = new string[]{ "a","b","c" },
  18. },
  19. new Person()
  20. {
  21. Id = "6",
  22. Firstname = "Aberdeen #110",
  23. Lastname = "sales@historichousehotels.com",
  24. Chains = new string[]{ "a","b","c" },
  25. },
  26. new Person()
  27. {
  28. Id = "7",
  29. Firstname = "Aberdeen #110",
  30. Lastname = "t Boterhuis 2",
  31. Chains = new string[]{ "a","b","c" },
  32. },
  33. };
  34. foreach (var person in persons)
  35. {
  36. client.Index(person);
  37. }

Person的类:

  1. public class Person
  2. {
  3. public string Id { get; set; }
  4. public string Firstname { get; set; }
  5. public string Lastname { get; set; }
  6. public string[] Chains { get; set; }
  7. }

好了,让我们来测试下排序~

  1).ID排序

  正常!

var searchResults = client.Search<Person>(s => s

.Index("zhixiao-application")

.Sort(sort => sort.OnField(f => f.Id).Order(SortOrder.Ascending))

);

2.字符串排序

咦,奇怪,数据哪里去了呢?刚才ID的排序正常,为啥这里就不正常了呢?

我们先断点看下:

可以看到,ConnnectionStatus的status code是200,说明连接成功,但是我们又没有查询出数据来,接下来就需要我们的header工具了

在最后一个tab中,header工具允许我们将ConnectionStatus.Request中的json用于查询,以此来验证对错。我们可以看到,查询的时候报了一个错误

Can't sort on string types with more than one value per doc, or more than one token per field

因为我们的数据是

这样的,在解析的时候,firstname会被analyse成多个term,所以在排序的时候,就会出错。

那么我们要怎么办呢?

http://blog.wiercinski.net/2011/uncategorized/elasticsearch-sorting-on-string-types-with-more-than-one-value-per-doc-or-more-than-one-token-per-field/

在这里我找到了一些答案,我们需要将一个我们需要排序的字段mapping成两个不同的字段,一个经过分析(e.g. firstname),一个没有经过分析(e.g. firtname.sort ).

在NEST中,有一个简便的方法,就是在你需要排序的属性上面加一个Attribute

[ElasticProperty(AddSortField = true)]

所以我们先将原先的索引删除,然后重新添加索引。

client.Map<Person>(m => m.MapFromAttributes());

这句代码很重要(在调用它之前需要先CreateIndex),它根据ElasticProperty对对象进行了mapping,使得firstname变成了一个multi fields,这点我们可以从      Request的Json中红色部分看出

{"person": {"properties": {"id": {"type": "string"},"firstname": {"type": "multi_field","fields": {"firstname": {"type": "string"},"sort": {"index": "not_analyzed","type": "string"}}},"lastname": {"type": "string"},"chains": {"type": "string"}}}
}

另外在header中可以发现,属性中多了一个person.firstname.sort

所以我们现在可以使用这个属性来进行排序了

代码如下:

var searchResults = client.Search<Person>(s => s

.Index("zhixiao-application")

.Sort(sort => sort.OnField(f => f.Firstname.Suffix("sort")).Ascending())

);

PS:注意上面红色部分的代码

排序结果如下:

成功!

3.距离排序

Elastic Search 自带了距离的排序和距离的筛选。所以我们只需要将索引建好,就可以使用。

好了,下面我们就一步步来进行:

(1)创建model
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public  class  Location
{
     public  string  Name {  get set ; }
     [ElasticProperty(Type = FieldType.GeoPoint)]
     public  Coordinate Coordinate {  get set ; }
}
public  class  Coordinate
{
     public  double  Lat {  get set ; }
     public  double  Lon {  get set ; }
}

PS:[ElasticProperty(Type = FieldType.GeoPoint)]这个attribute是为了下面mapping的时候,ES会将其识别为GeoPoint

(2)创建索引并且mapping
1
2
3
4
5
6
7
8
client.CreateIndex( "geopoint-tests" , s => s
     .AddMapping<Location>(f => f
     .MapFromAttributes()
     .Properties(p => p
         .GeoPoint(g => g.Name(n => n.Coordinate).IndexLatLon())
      )
    )
);

下面是创建索引并且mapping的request json: 

{"settings": {"index": { }},"mappings": {"location": {"properties": {"name": {"type": "string"},"coordinate": {"type": "geo_point","lat_lon": true}}}}
}

(3)创建数据:为了方便大家看出来正确的排序,我将latitude设置成一样的,这样可以一眼就看出来排序的对错
client.IndexMany(new[]
{createLocation("1", 52.310551, 5.07039),createLocation("2", 52.310551, 10.761176),createLocation("3", 52.310551, 8.07039),createLocation("4", 52.310551, 6.07039),});private static Location createLocation(string name, double latitude, double longitude){return new Location{Name = name,Coordinate = new Coordinate { Lat = latitude, Lon = longitude }};}

  (4)排序的使用:

  1. var results = client.Search<Location>(s => s
  2. .SortGeoDistance(sort => sort.OnField("coordinate").PinTo(52.310551, 4.404954).Ascending()));

  结果:

  

  成功!

4.距离Filter(其实这个应该分类在query中,不过这个需要在上面排序的代码上面做修改,所以就放到这里了)

  代码如下:

  1. var results = client.Search<Location>(s => s
  2. .Filter(f => f.GeoDistance("coordinate", fd => fd.Distance(100, GeoUnit.Kilometers).Location(52.310551, 4.404954)))
  3. .SortGeoDistance(sort => sort.OnField("coordinate").PinTo(52.310551, 4.404954).Ascending()));

  结果如下:

  

6.更新数据

由于比较简单,我就不解释啥了,直接上代码

            Person newperson = new Person(){Id = "7",Firstname = "Aberdeen #110",Lastname = "Update",Chains = new string[] { "a", "b", "c" },};UpdateRequest<Person> updateRequest = new UpdateRequest<Person>(7){Doc = newperson};IUpdateResponse updateResponse = updateClient.Update<Person, Person>(updateRequest);if (updateResponse.ConnectionStatus.HttpStatusCode != 200){updateClient.Index(newperson);}client.ClearCache();var searchResults = updateClient.Search<Person>(s => s.Index("zhixiao-application").Query(q => q.Term(t => t.OnField(f => f.Id).Value(7))));Console.WriteLine(searchResults.Documents.Count());foreach (var person in searchResults.Documents){Console.WriteLine(person.Id + "," + person.Lastname);}

PS:需要注意的是,如果你需要清除一个属性的值,传入null会导致ES认为你不需要更新这个属性,所以清除一个属性的值我们需要传入一个""。

7.删除数据
//delete one by id

updateClient.Delete<Person>(d => d.Id(7));

//delete one by object

updateClient.Delete<Person>(new Person() { });

//delete the Indices

updateClient.DeleteIndex(new DeleteIndexRequest(new IndexNameMarker() { Name = "zhixiao-application", Type = typeof(Person) }));

转载于:https://www.cnblogs.com/a-du/p/7603138.html

ElasticSearch NEST笔记相关推荐

  1. ElasticSearch启动报错curl: (7) Failed connect to 172.19.128.56:9200; 拒绝连接---ElasticSearch工作笔记029

    注意这里如果是在centos7系统中访问: curl http://localhost:9200/ 的时候也会报错,说拒绝连接,那么这个时候,就可能是 ElasticSearch工作笔记028 中说的 ...

  2. elasticSearch学习笔记04-同义词,停用词,拼音,高亮,拼写纠错

    由于elasticSearch版本更新频繁,此笔记适用ES版本为 7.10.2 此笔记摘录自<Elasticsearch搜索引擎构建入门与实战>第一版 文中涉及代码适用于kibana开发工 ...

  3. # nest笔记四:文件的上传与下载

    nest笔记四:文件的上传与下载 nest是基于express之上的,所以,其文件上传和下载的功能,实际上就是express的功能. 下载 文件下载有两种,一个是sendFile,一个是downloa ...

  4. ElasticSearch 学习笔记:Multi Search

    本文目录 1 简介 2 格式 3 header格式 4 body格式 5 返回格式 6 性能 7 相关文章 1 简介 批量查询接口(Multi Search API)允许在一次请求中执行多个查询操作, ...

  5. Elasticsearch进阶笔记

    Elasticsearch进阶笔记 6.ES的核心概念 1.概述 2.Elasticsearch核心概念 1.索引 index 2.类型 type 3.字段Field 4.映射 mapping 5.文 ...

  6. nest笔记七:参数校验

    nest笔记七:参数校验 nestjs的参数校验官方文档:https://docs.nestjs.com/techniques/validation. 它主要使用第三方的class-validator ...

  7. ElasticSearch学习笔记-ngram、中文拼音、简繁体搜索记录

    ElasticSearch版本:elasticsearch-7.3.0 ElasticSearch相关插件安装可以参考: ElasticSearch学习笔记-插件安装记录_人生偌只如初见的博客-CSD ...

  8. nest笔记十:typeorm使用经验小结

    nest笔记十:typeorm使用经验小结 nestjs系列笔记 之前的笔记:nest记笔五:使用TypeORM连接mysql,可以使用typeorm的基本功能.随着开发的深入,很多已经满足不了要求了 ...

  9. ElasticSearch学习笔记之十一 Anayle API和IK分词器

    ElasticSearch学习笔记之十一 Anayle API和IK分词器 Anayle API IK分词器 IK分词器版本支持 安装 下载或者编译 选择一 选择二 重启ElasticSearch I ...

  10. ElasticSearch学习笔记之二十一 指标聚合

    ElasticSearch学习笔记之二十一 指标聚合 指标聚合 Avg Aggregation Script Value Script Missing value Weighted Avg Aggre ...

最新文章

  1. OpenStack Nova Release(Rocky to Train)
  2. NR 5G 关于gNB-CU和gNB-DU
  3. lucene Index Store TermVector 说明
  4. python时间段_python--时间段遍历
  5. 【转】Elasticsearch+Django搜索引擎(二)
  6. (二)关于ThinkPHP2.1版本操作MSSQL类的BUG--selec查询只得出1条记录
  7. Golang 性能分析工具简要介绍
  8. python登陆linkedin过程分析,及二次验证(一)
  9. 十年磨一剑:梳理淘宝网技术架构的发展
  10. 【Uplift】模拟数据篇
  11. 前端之JS事件events
  12. 关于“元宇宙”,讲点你能听懂的
  13. Jqury基础大汇总来啦~
  14. stm32USB之模拟U盘
  15. 【积水成渊-逐步定制自己的Emacs神器】6:首次变身IDE,Emacs C++ IDE
  16. 【Unity3D 灵巧小知识点】 ☀️ | 求解 两个向量的夹角度数
  17. 数据库开发-8-并发处理
  18. C++入门——实现见缝插针游戏
  19. kubernetes挂载ceph rbd和cephfs
  20. matlab矩阵行位列维,如何在Matlab中对行矩阵的元素进行不等长度分组

热门文章

  1. 能够在乱世中_古代乱世中,为什么许多能人自己不当带头人,却要辅助别人
  2. 留学本科没毕业你也对留学的价值产生怀疑了吗?
  3. UltraScale FPGA 可编程逻辑块(CLB)
  4. 【商务英语】用谈恋爱的方式找工作
  5. NOTA-NH2/COOH/Mal/NHS/N3/OH/Alkyne/CHO/SH大环配体-氨基/羧基/马来酰亚胺/活性酯/叠氮/羟基/炔基/醛基/疏基
  6. 关于Mac远程ssh免密链接Centos的方法
  7. 从智能手机到智能机器人:小米品牌的高端化之路
  8. 感知环境、智慧环保——开启生态环保大数据智慧时代
  9. 高质量泛光(Bloom)从理论到实战
  10. 【网络基础篇】8.华为交换机上如何禁用接口g0/0/1