net平台下c#操作ElasticSearch详解

ElasticSearch系列学习

ElasticSearch第一步-环境配置

ElasticSearch第二步-CRUD之Sense

ElasticSearch第三步-中文分词

ElasticSearch第四步-查询详解

ElasticSearch第五步-.net平台下c#操作ElasticSearch详解

前面我们讲解了关于ElasticSearch的安装配置,以及CRUD

本章我将讲解怎么使用c#操作ElasticSearch。

首先你需要一定的技术储备,比如:asp.net webapi,mvc,jsonp,knockout。这些知识在这里不再讲解,请自行Google。

项目DEMO介绍

搜索和索引功能我是以服务(webapi项目)方式提供的,在客户端(mvc项目)中的view视图中,直接使用ajax(jsonp格式)方式调用webapi,然后使用knockout绑定到table上的。

项目结构如图:

引入驱动

工欲善其事必先利其器,首先我们需要在Supernova.Webapi层中引入操作ElasticSearch的驱动dll PlainElastic.Net。

如图:

封装操作ElasticSearch的ElasticSearchHelper

 

demo中涉及的实体对象模型

详细介绍ElasticSearchHelper里面的方法

1.索引文档(注意:索引文档之前先用配置filed对应的ik分词):

 public IndexResult Index(string indexName, string indexType, string id, string jsonDocument)
{ var serializer = new JsonNetSerializer();
string cmd = new IndexCommand(indexName, indexType, id);
OperationResult result = Client.Put(cmd, jsonDocument); var indexResult = serializer.ToIndexResult(result.Result);
return indexResult;
}
public IndexResult Index(string indexName, string indexType, string id, object document)
{
var serializer = new JsonNetSerializer();
var jsonDocument = serializer.Serialize(document);
return Index(indexName, indexType, id, jsonDocument);
}

2.对单个字段的全文检索,字段intro 包含词组key中的任意一个单词。例如:词组(中国美好),只要每条数据的intro字段包含"中国"或者"美好"就返回。

public personList Search<person>(string indexName, string indexType, string key,int from ,int size)
{
string cmd = new SearchCommand(indexName, indexType);
string query = new QueryBuilder<person>()
//1 查询
.Query(b =>
b.Bool(m =>
//并且关系
m.Must(t => //分词的最小单位或关系查询
t.QueryString(t1=>t1.DefaultField("intro").Query(key))
//.QueryString(t1 => t1.DefaultField("name").Query(key))
// t .Terms(t2=>t2.Field("intro").Values("研究","方鸿渐"))
//范围查询
// .Range(r => r.Field("age").From("100").To("200") )
)
)
)
//分页
.From(from)
.Size(size)
//排序
// .Sort(c => c.Field("age", SortDirection.desc))
//添加高亮
.Highlight(h => h
.PreTags("<b>")
.PostTags("</b>")
.Fields(
f => f.FieldName("intro").Order(HighlightOrder.score),
f => f.FieldName("_all")
)
)
.Build(); string result = Client.Post(cmd, query);
var serializer = new JsonNetSerializer();
var list = serializer.ToSearchResult<Supernova.Webapi.DbHelper.person>(result);
personList datalist = new personList();
datalist.hits = list.hits.total;
datalist.took = list.took;
var personList= list.hits.hits.Select(c => new Supernova.Webapi.DbHelper.person() {
id=c._source.id,
age=c._source.age,
birthday =c._source.birthday,
intro=string.Join("",c.highlight["intro"]), //高亮显示的内容,一条记录中出现了几次
name=c._source.name,
sex=c._source.sex, });
datalist.list.AddRange(personList);
return datalist; }

3.字段intro 或者name 包含词组key中的所有单词。例如:词组(中国美好),只要每条数据的intro或者name字段包含"中国"并且包含"美好"就返回。

   public personList SearchFullFileds<person>(string indexName, string indexType, string key, int from, int size)
{
MustQuery<person> mustNameQueryKeys = new MustQuery<person>();
MustQuery<person> mustIntroQueryKeys = new MustQuery<person>();
var arrKeys = GetIKTokenFromStr(key);
foreach (var item in arrKeys)
{
mustNameQueryKeys = mustNameQueryKeys.Term(t3 => t3.Field("name").Value(item)) as MustQuery<person>;
mustIntroQueryKeys = mustIntroQueryKeys.Term(t3 => t3.Field("intro").Value(item)) as MustQuery<person>;
} string cmd = new SearchCommand(indexName, indexType);
string query = new QueryBuilder<person>()
//1 查询
.Query(b =>
b.Bool(m =>
m.Should(t =>
t.Bool(m1 =>
m1.Must(
t2 =>
//t2.Term(t3=>t3.Field("name").Value("研究"))
// .Term(t3=>t3.Field("name").Value("方鸿渐"))
mustNameQueryKeys
)
)
)
.Should(t =>
t.Bool(m1 =>
m1.Must(t2 =>
//t2.Term(t3 => t3.Field("intro").Value("研究"))
//.Term(t3 => t3.Field("intro").Value("方鸿渐"))
mustIntroQueryKeys
)
)
)
)
)
//分页
.From(from)
.Size(size)
//排序
// .Sort(c => c.Field("age", SortDirection.desc))
//添加高亮
.Highlight(h => h
.PreTags("<b>")
.PostTags("</b>")
.Fields(
f => f.FieldName("intro").Order(HighlightOrder.score),
f => f.FieldName("name").Order(HighlightOrder.score)
)
)
.Build(); string result = Client.Post(cmd, query);
var serializer = new JsonNetSerializer();
var list = serializer.ToSearchResult<Supernova.Webapi.DbHelper.person>(result);
personList datalist = new personList();
datalist.hits = list.hits.total;
datalist.took = list.took;
var personList = list.hits.hits.Select(c => new Supernova.Webapi.DbHelper.person()
{
id = c._source.id,
age = c._source.age,
birthday = c._source.birthday,
intro = c.highlight==null||!c.highlight.Keys.Contains("intro") ? c._source.intro : string.Join("", c.highlight["intro"]), //高亮显示的内容,一条记录中出现了几次
name = c.highlight==null||!c.highlight.Keys.Contains("name") ? c._source.name : string.Join("", c.highlight["name"]),
sex = c._source.sex });
datalist.list.AddRange(personList);
return datalist; }

3.搜索age在1到500之间,并且字段intro 或者name 包含词组key中的所有单词。

 public personList SearchFullFiledss<person>(string indexName, string indexType, string key, int from, int size)
{
MustQuery<person> mustNameQueryKeys = new MustQuery<person>();
MustQuery<person> mustIntroQueryKeys = new MustQuery<person>();
var arrKeys = GetIKTokenFromStr(key);
foreach (var item in arrKeys)
{
mustNameQueryKeys = mustNameQueryKeys.Term(t3 => t3.Field("name").Value(item)) as MustQuery<person>;
mustIntroQueryKeys = mustIntroQueryKeys.Term(t3 => t3.Field("intro").Value(item)) as MustQuery<person>;
} string cmd = new SearchCommand(indexName, indexType);
string query = new QueryBuilder<person>()
//1 查询
.Query(b =>
b.Bool(m =>
m.Must(t =>
t.Range(r => r.Field("age").From("1").To("500"))
.Bool(ms =>
ms.Should(ts =>
ts.Bool(m1 =>
m1.Must(
t2 =>
//t2.Term(t3=>t3.Field("name").Value("研究"))
// .Term(t3=>t3.Field("name").Value("方鸿渐"))
//
mustNameQueryKeys
)
)
)
.Should(ts =>
ts.Bool(m1 =>
m1.Must(t2 =>
//t2.Term(t3 => t3.Field("intro").Value("研究"))
//.Term(t3 => t3.Field("intro").Value("方鸿渐")) //
mustIntroQueryKeys
)
)
)
)
)
)
)
//分页
.From(from)
.Size(size)
//排序
// .Sort(c => c.Field("age", SortDirection.desc))
//添加高亮
.Highlight(h => h
.PreTags("<b>")
.PostTags("</b>")
.Fields(
f => f.FieldName("intro").Order(HighlightOrder.score),
f => f.FieldName("name").Order(HighlightOrder.score)
)
)
.Build(); string result = Client.Post(cmd, query);
var serializer = new JsonNetSerializer();
var list = serializer.ToSearchResult<Supernova.Webapi.DbHelper.person>(result);
personList datalist = new personList();
datalist.hits = list.hits.total;
datalist.took = list.took;
var personList = list.hits.hits.Select(c => new Supernova.Webapi.DbHelper.person()
{
id = c._source.id,
age = c._source.age,
birthday = c._source.birthday,
intro = c.highlight==null||!c.highlight.Keys.Contains("intro") ? c._source.intro : string.Join("", c.highlight["intro"]), //高亮显示的内容,一条记录中出现了几次
name = c.highlight==null||!c.highlight.Keys.Contains("name") ? c._source.name : string.Join("", c.highlight["name"]),
sex = c._source.sex });
datalist.list.AddRange(personList);
return datalist; }

需要用到的方法:将语句用ik分词,返回分词结果的集合

 private List<string> GetIKTokenFromStr(string key)
{
string s = "/db_test/_analyze?analyzer=ik";
var result = Client.Post(s, "{"+key+"}");
var serializer = new JsonNetSerializer();
var list = serializer.Deserialize(result, typeof(ik)) as ik;
return list.tokens.Select(c=>c.token).ToList();
}

ASP.NET WebApi 调用ElasticSearchHelper

1.首先我们添加一个基类ApiController

 public class BaseApiController : ApiController
{ public MongoDatabase db;
public MongoCollection col = null;//用于直接返回查询的json
public BaseApiController() { }
public BaseApiController(string collectionName)
{
db = DbHelper.MongodbHelper.Instance.DB;
col = db.GetCollection(collectionName);
}
public string GetStringRequest(string paramter)
{
return HttpContext.Current.Request.QueryString[paramter] ?? "";
}
public int? GetIntRequest(string paramter)
{
string tmp = HttpContext.Current.Request.QueryString[paramter] ?? "";
int tag = 0;
if (!int.TryParse(tmp, out tag))
{
return null;
}
return tag;
}
}

2.操作ElasticSearch的apicontroller如下:

3.索引数据的api如下:

/// <summary>
/// 索引数据
/// </summary>
/// <returns></returns>
[Route("estest/index")]
[HttpGet]
public object index()
{
int length = S.test.Length;
Random rd = new Random();
Random rdName = new Random();
ParallelOptions _po = new ParallelOptions();
_po.MaxDegreeOfParallelism = 4;
Parallel.For(0, 10000000, _po, c =>
{ var start = rd.Next(0, S.test.Length - 700);
var startName = rd.Next(0, S.test.Length - 30);
person p = new person() { age = DateTime.Now.Millisecond, birthday = DateTime.Now, id = Guid.NewGuid().ToString(), intro = S.test.Substring(start, 629) + c, name = S.test.Substring(startName, 29) + c, sex = true };
ElasticSearchHelper.Intance.Index("db_test", "person", Guid.NewGuid().ToString(), p);
});
return 1;
}

索引使用的测试数据如下:

4.搜索api如下:

[Route("estest")]
[HttpGet]
public object Search()
{
//1 搜索数据
string key = GetStringRequest("Key");
int? from = GetIntRequest("from");
int? size = GetIntRequest("size"); return ElasticSearchHelper.Intance.Search<person>("db_test", "person", key ?? "方鸿渐", from == null ? 0 : from.Value, size == null ? 20 : size.Value); }
[Route("estest/SearchFullFileds")]
[HttpGet]
public object SearchFullFileds()
{
//1 搜索数据
string key = GetStringRequest("Key");
int? from = GetIntRequest("from");
int? size = GetIntRequest("size");
return ElasticSearchHelper.Intance.SearchFullFileds<person>("db_test", "person", key ?? "方鸿渐", from == null ? 0 : from.Value, size == null ? 20 : size.Value); }
[Route("estest/SearchFullFiledss")]
[HttpGet]
public object SearchFullFiledss()
{
//1 搜索数据
string key = GetStringRequest("Key");
int? from = GetIntRequest("from");
int? size = GetIntRequest("size");
return ElasticSearchHelper.Intance.SearchFullFiledss<person>("db_test", "person", key ?? "方鸿渐", from == null ? 0 : from.Value, size == null ? 20 : size.Value); }

WebSite中的view视图调用webapi

说明:我是直接使用ajax(jsop格式)调用webapi,返回的数据直接用knockout绑定到table中的。

视图代码如下:

@{
ViewBag.Title = "ElasticSearch测试";
Layout = null;
}
<link href="~/Content/bootstrap.css" rel="stylesheet" />
<script src="~/Scripts/jquery-2.1.3.min.js"></script>
<script src="~/Scripts/knockout-3.3.0.js"></script>
<style>
b{
color:red;
}
</style>
<script>
$(function () {
function ViewModel() {
self = this;
self.getData = ko.observableArray();
//定义加载数据方法
self.loadData = function () {
$.get("http://192.168.0.230/api/estest//SearchFullFiledss", { key: "@Request.QueryString["key"]", from: "@Request.QueryString["from"]", size: "@Request.QueryString["size"]" }, function (data) {
// alert(data.hits);
// alert(data.list.length);
$("#count").text("符合条件的数据供:" + data.hits + " 共花费了:" + data.took + "毫秒"); $.each(data.list, function (i) {
var date=data.list[i].birthday; });
self.getData(data.list);
}, "jsonp");
};
//调用定义方法
self.loadData();
}
ko.applyBindings(new ViewModel()); }); </script>
<div id="count"></div> <div class="row">
<table class="table-bordered table-condensed table-hover table-striped">
<tbody data-bind="foreach: getData">
<tr>
<td data-bind="text: id" />
<td data-bind="html: name" />
<td data-bind="text: sex" />
<td data-bind="text: age" />
<td data-bind="text: birthday" />
<td data-bind="html: intro" />
</tr>
</tbody>
</table>
</div>
<script> </script>

搜索结果测试如下(我是用"api/estest//SearchFullFiledss"这个api测试的,搜索age在1到500之间,并且字段intro 或者name 包含词组key中的所有单词。):

1.首先我们看一看测试数据总共有多少:

我们可以看到总共db_test中总共有两千多万条数据。

搜索测试1

测试条件:key=上海方鸿渐&from=0&size=100,key指搜索关键短语,0是从第0条开始区数据,100是指取一百条数据,隐藏条件是age大于1小于500

我们可以看到,首次搜索时,两千多万条数据大约耗时3.5秒,这里还包括取100条数据的时间,如果把数据改为20条则会更快。这里的硬件配置还只限于我的本机测试(内存8G,处理器Intel i5-4590 3.3GHZ)。

搜索测试2

测试条件同测试1:key=上海方鸿渐&from=0&size=100,key指搜索关键短语,0是从第0条开始区数据,100是指取一百条数据,隐藏条件是age大于1小于500

我们可以看到,搜索耗时降到了大约1.5秒。这说明同一个关键词搜索越频繁,搜索速度越快,这是因为ElasticSearch会自动将搜索的内容缓存到内存中。

搜索测试3

测试条件:key=香烟德国&from=0&size=20,key指搜索关键短语,0是从第0条开始区数据,20是指取一百条数据,隐藏条件是age大于1小于500

搜索测试4

测试条件同测试3,二次相同条件搜索:key=香烟德国&from=0&size=20,key指搜索关键短语,0是从第0条开始区数据,20是指取一百条数据,隐藏条件是age大于1小于500

我们可以看到,在二次搜索条件相同,搜索数据降低到20条的时候,只耗时不到0.5秒。

本章完……

ElasticSearch系列学习

ElasticSearch第一步-环境配置

ElasticSearch第二步-CRUD之Sense

ElasticSearch第三步-中文分词

ElasticSearch第四步-查询详解

ElasticSearch第五步-.net平台下c#操作ElasticSearch详解

NoSql系列

net平台下c#操作ElasticSearch详解的更多相关文章

  1. ElasticSearch-.net平台下c#操作ElasticSearch详解

    ElasticSearch系列学习 ElasticSearch第一步-环境配置 ElasticSearch第二步-CRUD之Sense ElasticSearch第三步-中文分词 ElasticSea ...

  2. ElasticSearch第五步-.net平台下c#操作ElasticSearch详解

    前面我们讲解了关于ElasticSearch的安装配置,以及CRUD 本章我将讲解怎么使用c#操作ElasticSearch. 首先你需要一定的技术储备,比如:asp.net webapi,mvc,j ...

  3. (转) unity 在移动平台中,文件操作路径详解

    http://www.unitymanual.com/thread-23491-1-1.html 今天,这篇文章其实是个老生常谈的问题咯,在网上类似的文章也比比皆是,在此我只是做个详细总结方便大家能够 ...

  4. unity 在移动平台中,文件操作路径详解

    今天,这篇文章其实是个老生常谈的问题咯,在网上类似的文章也比比皆是,在此我只是做个详细总结方便大家能够更好.更快的掌握,当然,如有不足的地方 欢迎指正!!! 相信大家在开发过程中,难免会保存一些文件在 ...

  5. c#操作ElasticSearch5详解

    c#操作ElasticSearch详解 ElasticSearch系列学习 ElasticSearch第一步-环境配置 ElasticSearch第二步-CRUD之Sense ElasticSearc ...

  6. Elasticsearch详解

    Elasticsearch详解 Chandler_珏瑜 关注  5.8 2019.05.05 17:19* 字数 10971 阅读 1147评论 5喜欢 36 5.1 Lucene简介  Lucene ...

  7. Elasticsearch详解-续

    Elasticsearch详解-续 Chandler_珏瑜  关注  7.6 2019.05.22 10:46* 字数 8366 阅读 675评论 4喜欢 25 5.3 性能调优  Elasticse ...

  8. 从原理到应用,Elasticsearch详解

    简介 Elasticsearch(简称ES)是一个分布式.可扩展.实时的搜索与数据分析引擎.ES不仅仅只是全文搜索,还支持结构化搜索.数据分析.复杂的语言处理.地理位置和对象间关联关系等. ES的底层 ...

  9. 【转帖】从原理到应用,Elasticsearch详解

    从原理到应用,Elasticsearch详解 https://segmentfault.com/a/1190000020022504 elasticsearch 2.1k 次阅读  ·  读完需要 4 ...

随机推荐

  1. sqlserver 删除表中 指定字符串

    源表T "单据编号"               "航班计划日期"        "航班号"          "起飞航站代码&q ...

  2. PHP中生产不重复随机数的方法

    PHP内置函数不重复随机数        需求:要生成一个数组,这个数组里面有10个元素,都是整形,并且是1-60之间不重复的随机数.  代码: 代码示例: 1 2 3 4 5 6 7 8 9 10 ...

  3. 4.7Python数据处理篇之Matplotlib系列(七)---matplotlib原理分析

    目录 目录 前言 (一)总框架分析 (二)函数式的绘图 1.说明: 2.函数绘图的缺优点 3.绘图类的函数 4.操作类的函数 5.例子: (三)面向对象式的绘图 1.基本概念 2.基本对象 3.面向对 ...

  4. LeetCode算法题-Pascal's Triangle II(Java实现)

    这是悦乐书的第171次更新,第173篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第30题(顺位题号是119).给定非负索引k,其中k≤33,返回Pascal三角形的第k ...

  5. MYSQL基本操作(上)

    很久之前,就想做个Mysql的小结,毕竟数据库知识是软件研发的基本技能,这里话不多说,开始总结一波. 数据库基本概念 数据库为高效的存储和处理数据的介质(主要分为磁盘和内存两种),一般关系型数据库存储 ...

  6. IE9样式错乱,IE11无法正常加载v-loading等问题 引入了babel-polyfill插件,依然出现”polyfill-eventsource added missing EventSource to window”的奇怪问题(ie所有版本都有出现)

    第一步:安装babel-ployfill (已安装请跳过此步骤) yarn add babel-ployfill 修改webpack打包配置文件:webpack.bash.conf.js // 引入b ...

  7. Spring Web项目spring配置文件随服务器启动时自动加载

    前言:其实配置文件不随服务器启动时加载也是可以的,但是这样操作的话,每次获取相应对象,就会去读取一次配置文件,从而降低程序的效率,而Spring中已经为我们提供了监听器,可监听服务器是否启动,然后在启 ...

  8. java实现谷歌二步验证 (Google Authenticator)

    准备: 一个谷歌二步验证APP,  我用的是ios 身份宝 资料: 1.Google Authenticator 原理及Java实现   //主要参考 https://blog.csdn.net/li ...

  9. console命令的其他强大用法

    阅读目录 谷歌控制台Elements面板查看元素上绑定的事情样式操作总况console.logconsole.infoconsole.errorconsole.warnconsole.debugcon ...

  10. Apache 项目列表功能分类便于技术选型

    big-data (49):  Apache Accumulo  Apache Airavata  Apache Ambari  Apache Apex  Apache Avro  Apache Be ...