ElasticSearch7.x系列二:Kibana的使用和C#的Nest客户端
目录
前言
ElasticSearch,Kibana,Logstash等安装上一章讲完了,这一章讲讲ELasticSearch怎么使用
两种方式,一种是直接写ElasticSearch查询语句,当然是在Kibana里面
还有一种是用代码写,可以用Java,C#,PHP,Python等,我这里使用C#
Kibana查询ElasticSearch
#创建
PUT /test/user/1
{
"name":"许嵩",
"age":34,
"tags":["a","b","c"]
}
#查询index里面的数量
GET test/_count
#查询id为1的
GET test/user/1
#查询name包含许嵩的
GET article/_search?q=title:许嵩
# 也可以使用这种
GET article/_search
{
"query": {
"match": {
"title": "许嵩"
}
}
}
# 高亮查询,讲一下,所谓的高亮就是给关键字加上自己定义的一个标签,一般都是em,然后你在css里面定义em为高亮黄色或者红色即可
GET article/_search
{
"query": {
"match": {
"title": "许嵩"
}
},
"highlight": {
"pre_tags": [
"<em>"
],
"post_tags": [
"</em>"
],
"encoder": "html",
"fields": {
"title": {
"force_source": true,
"fragment_size": 150,
"fragmenter": "span",
"number_of_fragments": 3,
"no_match_size": 150
}
}
}
}
# 更新
POST /test/user/1/_update
{
"doc":{
"name":"vae"
}
}
使用C#的Nest查询ElasticSearch
在NuGet里面下Nest
连接
var settings = new ConnectionSettings(new Uri("http://192.168.3.8:9200/")).DefaultIndex("article");
var client = new ElasticClient(settings);
使用连接池
可以多搞几个ElasticSearch服务器
var uris = new[]
{
new Uri("http://localhost:9200"),
new Uri("http://localhost:9201"),
new Uri("http://localhost:9202"),
};
var connectionPool = new SniffingConnectionPool(uris);
var settings = new ConnectionSettings(connectionPool)
.DefaultIndex("people");
var client = new ElasticClient(settings);
增加文档
var person = new Person
{
Id = 1,
FirstName = "Martijn",
LastName = "Laarman"
};
//同步
var indexResponse = client.IndexDocument(person);
//异步
var asyncIndexResponse = await client.IndexDocumentAsync(person);
批量增加文档
var bulkAllObservable = client.BulkAll(list, b => b
.Index("article")
.BackOffTime("30s")
.BackOffRetries(2)
.RefreshOnCompleted()
.MaxDegreeOfParallelism(Environment.ProcessorCount)
.Size(1000)
)
.Wait(TimeSpan.FromMinutes(15), next =>
{
// do something e.g. write number of pages to console
});
搜索文档
- From(0) 从0开始
- Size(10) 每次找10个
- Query 查询
- Match 模糊匹配
- Field 字段
查询指定字段
比如我只查标题
var search = client.Search<AllInformationViewModel>(s => s
.Index(indexName)
.From(page)
.Size(10)
.Query(q => q
.Match(m => m
.Field(f => f.Title)
.Query(keyword))
全文检索
全文检索的意思就是全部字段我都查找,标题啊,描述啊,摘要啊
var searchAll = client.Search<AllInformationViewModel>(s => s
.Index(indexName)
.From(page)
.Size(10)
.Query(q => q
.QueryString(qs => qs
.Query(keyword).DefaultOperator(Operator.And))
全文检索高亮
我全文检索查的标题,描述都得给我高亮
#方法1
.Highlight(h => h
.PreTags("<em>")
.PostTags("</em>")
.Encoder(HighlighterEncoder.Html)
.Fields(
fs => fs
.Field(p => p.Title),
fs => fs
.Field(p => p.Content)
)
)
#方法2
.Highlight(h => h
.Fields(
fs => fs
.Field(p => p.Title)
.PreTags("<em>")
.PostTags("</em>"),
fs => fs
.Field(p => p.Content)
.PreTags("<em>")
.PostTags("</em>")
)
)
高亮查询
public ActionResult Index(string keywords="")
{
var settings = new ConnectionSettings(new Uri("http://192.168.3.8:9200/")).DefaultIndex("article");
var client = new ElasticClient(settings);
var search = client.Search<Article>(s => s
.From(0)
.Size(10)
.Query(q => q
.Match(m => m
.Field(f => f.Title)
.Query(keywords))
)
.Highlight(h => h.Fields(e => e.Field("title")
.PreTags("<b style='color:red'>")
.PostTags("</b>")))
//.Sort(r => r.Descending(q => q.CreateDate))
//在工作中把<b style='color:red'>这个换成em标签就可以了,然后在css里面给em加上高亮即可
);
foreach (var hit in search.Hits)
{
foreach (var highlightField in hit.Highlight)
{
if (highlightField.Key == "title")
{
foreach (var highlight in highlightField.Value)
{
hit.Source.Title = highlight.ToString();
}
}
}
}
return View(search.Documents);
}
聚合查询
var searchResponse = await client.SearchAsync<Person>(s => s
.Size(0)
.Query(q => q
.Match(m => m
.Field(f => f.FirstName)
.Query("许嵩")
)
)
.Aggregations(a => a
.Terms("last_names", ta => ta
.Field(f => f.LastName)
)
)
);
var termsAggregation = searchResponse.Aggregations.Terms("last_names");
结构化: 特点,查询结果要么是true要么是false
结构化一般查找时间,数字或者标题之类的,查询的答案始终是或否;文档是查询的匹配项,或者不是。
开始时间在2017年之间的所有数据
var searchResponse = _client.Search<Project>(s => s
.Query(q => q
.DateRange(r => r
.Field(f => f.StartTime)
.GreaterThanOrEquals(new DateTime(2017, 01, 01))
.LessThan(new DateTime(2018, 01, 01))
)
)
);
{
"query": {
"range": {
"startedOn": {
"lt": "2018-01-01T00:00:00",
"gte": "2017-01-01T00:00:00"
}
}
}
}
非结构化搜索: 特点,在全文字段中搜索
我们常用的搜索就是非结构化搜索,例如我搜一个人名
var searchResponse = _client.Search<Project>(s => s
.Query(q => q
.Match(m => m
.Field(f => f.Name)
.Query("许嵩")
)
)
);
组合查询
查找姓是 许 名是嵩的,并且时间必须在2017年
var searchResponse = _client.Search<Project>(s => s
.Query(q => q
.Bool(b => b
.Must(mu => mu
.Match(m => m
.Field(f => f.FirstName)
.Query("许")
), mu => mu
.Match(m => m
.Field(f => f.LastName)
.Query("嵩")
)
)
.Filter(fi => fi
.DateRange(r => r
.Field(f => f.StartedOn)
.GreaterThanOrEquals(new DateTime(2017, 01, 01))
.LessThan(new DateTime(2018, 01, 01))
)
)
)
)
);
{
"query": {
"bool": {
"must": [
{
"match": {
"leadDeveloper.firstName": {
"query": "Russ"
}
}
},
{
"match": {
"leadDeveloper.lastName": {
"query": "Cam"
}
}
}
],
"filter": [
{
"range": {
"startedOn": {
"lt": "2018-01-01T00:00:00",
"gte": "2017-01-01T00:00:00"
}
}
}
]
}
}
}
还有一个更好用的写法
searchResponse = _client.Search<Project>(s => s
.Query(q => q
.Match(m => m
.Field(f => f.FirstName)
.Query("许")
) && q
.Match(m => m
.Field(f => f.LastName)
.Query("嵩")
) && +q
.DateRange(r => r
.Field(f => f.StartedOn)
.GreaterThanOrEquals(new DateTime(2017, 01, 01))
.LessThan(new DateTime(2018, 01, 01))
)
)
);
组合记得使用 +
布尔查询
不好的写法
var searchResults = this.Client.Search<Project>(s => s
.Query(q => q
.Bool(b => b
.Should(
bs => bs.Term(p => p.Name, "x"),
bs => bs.Term(p => p.Name, "y")
)
)
)
);
这种写法很不好,如果很多bool嵌套查询,多个bool查询,结果是啥?结果就会像下图一样
你的代码会变成凹陷缩进的样子,很丑,而且不利于维护,看着就头大了
推荐使用的bool查询
var firstSearchResponse = client.Search<Project>(s => s
.Query(q => q
.Term(p => p.Name, "x") || q
.Term(p => p.Name, "y")
)
);
var firstSearchResponse = client.Search<Project>(s => s
.Query(q => q
.Term(p => p.Name, "x") && q
.Term(p => p.Name, "y")
)
);
var firstSearchResponse = client.Search<Project>(s => s
.Query(q => !q
.Term(p => p.Name, "x")
)
);
选择要返回的字段
我们查询不需要所有的字段,只需要几个字段就可以
查询全部的数据,但是只要Name和StartTime这两个字段
var searchResponse = _client.Search<Project>(s => s
.StoredFields(sf => sf
.Fields(
f => f.Name,
f => f.StartTime
)
)
.Query(q => q
.MatchAll()
)
);
源筛选
var searchResponse = _client.Search<Project>(s => s
.Source(sf => sf
.Includes(i => i //包括以下字段
.Fields(
f => f.Name,
f => f.StartedOn
)
)
.Excludes(e => e
.Fields("num*") //排除其他字段
)
)
.Query(q => q
.MatchAll()
)
);