快速入門
Elasticsearch 快速入門
ElasticSearch 是一個開源的搜索引擎,建立在一個全文搜索引擎庫 Apache Lucene? 基礎之上, Lucene 可以說是當下最先進、高性能、全功能的搜索引擎庫,無論是開源還是私有,
但是 Lucene 僅僅只是一個庫,為了充分發揮其功能,你需要使用 Java 并將 Lucene 直接集成到應用程式中, 更糟糕的是,您可能需要獲得資訊檢索學位才能了解其作業原理,Lucene 非常 復雜,
ElasticSearch 也是使用 Java 撰寫的,它的內部使用 Lucene 做索引與搜索,但是它的目的是使全文檢索變得簡單, 通過隱藏 Lucene 的復雜性,取而代之的提供一套簡單一致的 RESTful API,
然而,Elasticsearch 不僅僅是 Lucene,并且也不僅僅只是一個全文搜索引擎, 它可以被下面這樣準確的形容:
- 一個分布式的實時檔案存盤,每個欄位 可以被索引與搜索
- 一個分布式實時分析搜索引擎
- 能勝任上百個服務節點的擴展,并支持 PB 級別的結構化或者非結構化資料
官方客戶端在Java、.NET、PHP、Python、Ruby、Nodejs和許多其他語言中都是可用的,根據 DB-Engines 的排名顯示,ElasticSearch 是最受歡迎的企業搜索引擎,其次是Apache Solr,也是基于Lucene,
ES 開發指南
中文檔案請參考:《Elasticsearch: 權威指南》
英文檔案請參考:《Elasticsearch Reference》
下載: https://www.elastic.co/cn/downloads/
ES API檔案
API Conventions
Document APIs
Search APIs
Indices APIs
cat APIs
Cluster APIs
Javascript api
Logstash
Logstash Reference
Configuring Logstash
Input plugins
Output plugins
Filter plugins
Kibana DevTools 快捷鍵
- Ctrl+i 自動縮進
- Ctrl+Enter 提交
- Down 打開自動補全選單
- Enter 或 Tab 選中項自動補全
- Esc 關閉補全選單
pretty = true在任意的查詢字串中增加pretty引數,會讓 Elasticsearch 美化輸出(pretty-print)JSON回應以便更加容易閱讀,
Kibana 命令
// 查詢集群的磁盤狀態
GET _cat/allocation?v
// 獲取所有索引
GET _cat/indices
// 按索引數量排序
GET _cat/indices?s=docs.count:desc
GET _cat/indices?v&s=index
// 集群有多少節點
GET _cat/nodes
// 集群的狀態
GET _cluster/health?pretty=true
GET _cat/indices/*?v&s=index
//獲取指定索引的分片資訊
GET logs/_search_shards
...
集群狀態
curl -s -XGET 'http://<host>:9200/_cluster/health?pretty'
//系統正常,回傳的結果
{
"cluster_name" : "es-qwerty",
"status" : "green",
"timed_out" : false,
"number_of_nodes" : 3,
"number_of_data_nodes" : 3,
"active_primary_shards" : 1,
"active_shards" : 2,
"relocating_shards" : 0,
"initializing_shards" : 0,
"unassigned_shards" : 0,
"delayed_unassigned_shards" : 0,
"number_of_pending_tasks" : 0,
"number_of_in_flight_fetch" : 0,
"task_max_waiting_in_queue_millis" : 0,
"active_shards_percent_as_number" : 100.0
}
檢索檔案
POST logs/_search
{
"query":{
"range":{
"createdAt":{
"gt":"2020-04-25",
"lt":"2020-04-27",
"format": "yyyy-MM-dd"
}
}
},
"size":0,
"aggs":{
"url_type_stats":{
"terms": {
"field": "urlType.keyword",
"size": 2
}
}
}
}
POST logs/_search
{
"query":{
"range":{
"createdAt":{
"gte":"2020-04-26 00:00:00",
"lte":"now",
"format": "yyyy-MM-dd hh:mm:ss"
}
}
},
"size":0,
"aggs":{
"url_type_stats":{
"terms": {
"field": "urlType.keyword",
"size": 2
}
}
}
}
POST logs/_search
{
"query":{
"range": {
"createdAt": {
"gte": "2020-04-26 00:00:00",
"lte": "now",
"format": "yyyy-MM-dd hh:mm:ss"
}
}
},
"size" : 0,
"aggs":{
"total_clientIp":{
"cardinality":{
"field": "clientIp.keyword"
}
},
"total_userAgent":{
"cardinality": {
"field": "userAgent.keyword"
}
}
}
}
POST logs/_search
{
"size" : 0,
"aggs":{
"date_total_ClientIp":{
"date_histogram":{
"field": "createdAt",
"interval": "quarter",
"format": "yyyy-MM-dd",
"extended_bounds":{
"min": "2020-04-26 13:00:00",
"max": "2020-04-26 14:00:00",
}
},
"aggs":{
"url_type_api": {
"terms": {
"field": "urlType.keyword",
"size": 10
}
}
}
}
}
}
POST logs/_search
{
"size" : 0,
"aggs":{
"total_clientIp":{
"terms":{
"size":30,
"field": "clientIp.keyword"
}
}
}
}
洗掉檔案
// 洗掉
POST logs/_delete_by_query {"query":{"match_all": {}}}
// 洗掉索引
DELETE logs
創建索引
資料遷移本質是索引的重建,重建索引不會嘗試設定目標索引,它不會復制源索引的設定, 所以在操作之前設定目標索引,包括設定映射,分片數,副本等,
資料遷移
Reindex from Remoteedit
// Reindex支持從遠程Elasticsearch集群重建索引:
POST _reindex
{
"source": {
"remote": {
"host": "http://lotherhost:9200",
"username": "user",
"password": "pass"
},
"index": "source",
"query": {
"match": {
"test": "data"
}
}
},
"dest": {
"index": "dest"
}
}
// host引數必須包含scheme、host和port(例如https://lotherhost:9200)
// username和password引數可選
使用時需要在elasticsearch.yml中配置 reindex.remote.whitelist 屬性,可以設定多組(例如,lotherhost:9200, another:9200, 127.0.10.*:9200, localhost:*),
具體使用可參考 Reindex from Remoteedit
Elasticsearch-Dump
Elasticsearch-Dump是一個elasticsearch資料匯入匯出開源工具包,安裝、遷移相關執行可以在相同可用區的云主機上進行,使用方便,
需要node環境,npm安裝elasticdump
npm install elasticdump -g
elasticdump
// Copy an index from production to staging with analyzer and mapping:
elasticdump \
--input=http://production.es.com:9200/my_index \
--output=http://staging.es.com:9200/my_index \
--type=analyzer
elasticdump \
--input=http://production.es.com:9200/my_index \
--output=http://staging.es.com:9200/my_index \
--type=mapping
elasticdump \
--input=http://production.es.com:9200/my_index \
--output=http://staging.es.com:9200/my_index \
--type=data
// Copy a single shard data:
elasticdump \
--input=http://es.com:9200/api \
--output=http://es.com:9200/api2 \
--params='{"preference" : "_shards:0"}'
elasticdump 命令其他引數使用參考 Elasticdump Options
深度分頁
- elasticsearch 超過10000條資料的分頁查詢會報例外,官方提供了 search_after 的方式來支持
- search_after 要求提供上一頁兩個必須的排序標識
//https://www.elastic.co/guide/en/elasticsearch/reference/5.6/search-request-search-after.html
GET logs/_search
{
"from":9990,
"size":10,
"_source": ["url","clientIp","createdAt"],
"query":{
"match_all": {}
},
"sort":[
{
"createdAt":{
"order":"desc"
}
},
{
"_id":{
"order":"desc"
}
}
]
}
GET logs/_search
{
"from":-1,
"size":10,
"_source": ["url","clientIp","createdAt"],
"query":{
"match_all": {}
},
"search_after": [1588042597000, "V363vnEBz1D1HVfYBb0V"],
"sort":[
{
"createdAt":{
"order":"desc"
}
},
{
"_id":{
"order":"desc"
}
}
]
}
安裝
- docker下安裝Elasticsearch
docker pull docker.elastic.co/elasticsearch/elasticsearch:7.8.1
docker run -p 9200:9200 --name elasticsearch -p 9300:9300 -e "discovery.type=single-node" docker.elastic.co/elasticsearch/elasticsearch:7.8.1
docker pull docker.elastic.co/kibana/kibana:7.8.1
docker run -p 5601:5601 --name kibana --link 14e385b1e761:elasticsearch -e "elasticsearch.hosts=http://127.0.0.1:9200" -d docker.elastic.co/kibana/kibana:7.8.1
- 其它平臺安裝Elasticsearch
接入使用
新建一個webapi專案,然后安裝兩個組件,
Install-Package NEST
Install-Package Swashbuckle.AspNetCore
通過NEST來實作操作Elasticsearch,開源地址:https://github.com/elastic/elasticsearch-net,同時將swagger也添加以下方便后面呼叫介面,
接下來演示一個對Elasticsearch的增刪改查操作,
添加物體類:VisitLog.cs,
using System;
namespace ESDemo.Domain
{
public class VisitLog
{
public string Id { get; set; }
/// <summary>
/// UserAgent
/// </summary>
public string UserAgent { get; set; }
/// <summary>
/// Method
/// </summary>
public string Method { get; set; }
/// <summary>
/// Url
/// </summary>
public string Url { get; set; }
/// <summary>
/// Referrer
/// </summary>
public string Referrer { get; set; }
/// <summary>
/// IpAddress
/// </summary>
public string IpAddress { get; set; }
/// <summary>
/// Milliseconds
/// </summary>
public int Milliseconds { get; set; }
/// <summary>
/// QueryString
/// </summary>
public string QueryString { get; set; }
/// <summary>
/// Request Body
/// </summary>
public string RequestBody { get; set; }
/// <summary>
/// Cookies
/// </summary>
public string Cookies { get; set; }
/// <summary>
/// Headers
/// </summary>
public string Headers { get; set; }
/// <summary>
/// StatusCode
/// </summary>
public int StatusCode { get; set; }
/// <summary>
/// Response Body
/// </summary>
public string ResponseBody { get; set; }
public DateTimeOffset CreatedAt { get; set; } = DateTimeOffset.UtcNow;
}
}
確定好物體類后,來包裝一下Elasticsearch,簡單封裝一個基類用于倉儲的集成使用,
添加一個介面類IElasticsearchProvider,
using Nest;
namespace ESDemo.Elasticsearch
{
public interface IElasticsearchProvider
{
IElasticClient GetClient();
}
}
在ElasticsearchProvider中實作IElasticsearchProvider介面,
using Nest;
using System;
namespace ESDemo.Elasticsearch
{
public class ElasticsearchProvider : IElasticsearchProvider
{
public IElasticClient GetClient()
{
var connectionSettings = new ConnectionSettings(new Uri("http://localhost:9200"));
return new ElasticClient(connectionSettings);
}
}
}
添加Elasticsearch倉儲基類,ElasticsearchRepositoryBase,
using Nest;
namespace ESDemo.Elasticsearch
{
public abstract class ElasticsearchRepositoryBase
{
private readonly IElasticsearchProvider _elasticsearchProvider;
public ElasticsearchRepositoryBase(IElasticsearchProvider elasticsearchProvider)
{
_elasticsearchProvider = elasticsearchProvider;
}
protected IElasticClient Client => _elasticsearchProvider.GetClient();
protected abstract string IndexName { get; }
}
}
也就是一個抽象類,當我們集成此基類的時候需要重寫protected abstract string IndexName { get; },指定IndexName,
完成上面簡單封裝,現在新建一個IVisitLogRepository倉儲介面,里面添加四個方法:
using ESDemo.Domain;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace ESDemo.Repositories
{
public interface IVisitLogRepository
{
Task InsertAsync(VisitLog visitLog);
Task DeleteAsync(string id);
Task UpdateAsync(VisitLog visitLog);
Task<Tuple<int, IList<VisitLog>>> QueryAsync(int page, int limit);
}
}
所以接下來不用說你也知道改干嘛,實作這個倉儲介面,添加VisitLogRepository,代碼如下:
using ESDemo.Domain;
using ESDemo.Elasticsearch;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace ESDemo.Repositories
{
public class VisitLogRepository : ElasticsearchRepositoryBase, IVisitLogRepository
{
public VisitLogRepository(IElasticsearchProvider elasticsearchProvider) : base(elasticsearchProvider)
{
}
protected override string IndexName => "visitlogs";
public async Task InsertAsync(VisitLog visitLog)
{
await Client.IndexAsync(visitLog, x => x.Index(IndexName));
}
public async Task DeleteAsync(string id)
{
await Client.DeleteAsync<VisitLog>(id, x => x.Index(IndexName));
}
public async Task UpdateAsync(VisitLog visitLog)
{
await Client.UpdateAsync<VisitLog>(visitLog.Id, x => x.Index(IndexName).Doc(visitLog));
}
public async Task<Tuple<int, IList<VisitLog>>> QueryAsync(int page, int limit)
{
var query = await Client.SearchAsync<VisitLog>(x => x.Index(IndexName)
.From((page - 1) * limit)
.Size(limit)
.Sort(x => x.Descending(v => v.CreatedAt)));
return new Tuple<int, IList<VisitLog>>(Convert.ToInt32(query.Total), query.Documents.ToList());
}
}
}
現在去寫介面,添加一個VisitLogControllerAPI控制器,代碼如下:
using ESDemo.Domain;
using ESDemo.Repositories;
using Microsoft.AspNetCore.Mvc;
using System.ComponentModel.DataAnnotations;
using System.Threading.Tasks;
namespace ESDemo.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class VisitLogController : ControllerBase
{
private readonly IVisitLogRepository _visitLogRepository;
public VisitLogController(IVisitLogRepository visitLogRepository)
{
_visitLogRepository = visitLogRepository;
}
[HttpGet]
public async Task<IActionResult> QueryAsync(int page = 1, int limit = 10)
{
var result = await _visitLogRepository.QueryAsync(page, limit);
return Ok(new
{
total = result.Item1,
items = result.Item2
});
}
[HttpPost]
public async Task<IActionResult> InsertAsync([FromBody] VisitLog visitLog)
{
await _visitLogRepository.InsertAsync(visitLog);
return Ok("新增成功");
}
[HttpDelete]
public async Task<IActionResult> DeleteAsync([Required] string id)
{
await _visitLogRepository.DeleteAsync(id);
return Ok("洗掉成功");
}
[HttpPut]
public async Task<IActionResult> UpdateAsync([FromBody] VisitLog visitLog)
{
await _visitLogRepository.UpdateAsync(visitLog);
return Ok("修改成功");
}
}
}
大功告成,最后一步不要忘記在Startup.cs中添加服務,不然無法使用依賴注入,
...
services.AddSingleton<IElasticsearchProvider, ElasticsearchProvider>();
services.AddSingleton<IVisitLogRepository, VisitLogRepository>();
...
一切準備就緒,現在滿懷期待的運行專案,打開swagger界面,

按照新增、更新、洗掉、查詢的順序依次呼叫介面,新增可以多來幾次,因為默認是沒有資料的,多添加一點可以測驗分頁是否ok,這里就不再演示了,
如果你有安裝kibana,現在可以滿懷驚喜的去查看一下剛才添加的資料,
GET _cat/indices
GET visitlogs/_search
{}

可以看到,資料已經安安靜靜的躺在這里了,
本篇簡單介紹Elasticsearch在.NET Core中的使用,關于檢索資料還有很多語法沒有體現出來,如果在開發中需要用到,可以參考官方的各種資料查詢示例:https://github.com/elastic/elasticsearch-net/tree/master/examples
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/56107.html
標籤:.NET Core
上一篇:teechart畫瀑布圖怎么畫?
