Elasticsearch是一個基於Lucene的搜索服務器。
它提供了一個分布式多用戶能力的全文搜索引擎,基於RESTful web接口。Elasticsearch是用Java語言開發的,並作為Apache許可條款下的開放源碼發布,是一種流行的企業級搜索引擎。Elasticsearch用於雲計算中,能夠達到實時搜索,穩定,可靠,快速,安裝使用方便。
Sql: like %xxx% ,如果是大數據,就十分的慢(用索引提升效率但是還是比較慢)
ElasticSearch/Soir:搜索(百度,github,淘寶,電商)
1. ElasticSearch創始人
Doug Cutting :Lucene(基於Lucene封裝的搜索引擎:soir,ElasticSearch),全文檢索功能(開源)
大數據的兩個問題:存儲(GFS,NDFS),計算(MapReduce編程模型)
NDFS+MapReduce=Hadoop
Lucene是一套信息檢索工具包,jar包,不包括搜索引擎系統
- 索引結構
- 讀取索引的工具
- 排序
- 聯測
- 搜索規則(工具類)
Lucene和ElasticSearch關系 :ElasticSearch是基於Lucene做了一些封裝和增強(通過簡單的Restful Api來隱藏Lucene的復雜性,從而讓全文搜索變得簡單)
日志數據分析(ELK,elasticsearch搜索+logstash過濾+kibana可視化分析)
2. 對比其他搜索引擎
ElasticSearch:(RestFult APi)基於Lucene,全文搜索,結構化搜索,分析(高亮,實時糾錯,用戶畫像分析,數據清理)
Solr:(Web APi)基於Lucene,可以獨立運行(用post方法向Solr服務器發送一個描述Field及其內容的XML文檔,Slor根據XML文檔添加,刪除,更新索引),Solr不提供UI的功能,Solr提供一個管理界面,通過管理界面可以查詢Solr的配置和運行情況
Lucene:Lucene是一套java信息檢索工具包,jar包,不包括搜索引擎系統
ES和Solr的差別?
- 對單純已有的數據進行搜索,Solr更快
- 當實時建立索引時,Solr會產生io阻塞,查詢性能較差,ElasticSearch具有更明顯的優勢
- 隨着數據量的增加,Solr的搜索效率會變得更低,而ES無明顯變化
總結:
- es基本開箱即用,非常簡單,Solr安裝較為復雜
- Solr利用Zookeeper進行分布式管理,而es自身帶有分布式協調管理功能
- Solr支持更多格式的數據,如json,xml,csv,而es僅支持json
- Solr提供的功能很多,但es本身更注重核心功能,高級功能多有第三方插件提供,例如圖形化界面的kibana
- Solr查詢快,但更新索引時慢(即插入刪除慢),es為實時性查詢
- Solr比較成熟,es相對開發維護者較少,更新太快,學習成本較高
3. 安裝
- 安裝es
java版本:jdk1.8以上

node.js
python
npm

下載解壓即可

bin:啟動文件
config配置文件

- log4j2.properties:日志配置文件
- jvm.options:java虛擬機相關配置
- elasticsearch.yaml:es配置文件 默認9200端口!跨域
jdk:環境
lib:相關jar包lucene
modules:功能模塊
plugins:插件(ik分詞器)
logs:日志
啟動
雙擊bin/elasticsearch.bat文件

訪問127.0.0.1:9200

- 安裝可視化界面head
下載地址:https://github.com/mobz/elasticsearch-head


跨域問題(9100~9200)
es配置文件

重啟es服務查看head

索引就相當於一個數據庫(表就相當於一個文檔,類型相當於屬性)

這個head就當作是一個數據展示工具,我們后面所有的查詢可以在kabana做
- 安裝kibana(可視化平台)
ELK關系

- 收集清洗數據(Loastash)
- 搜索,存儲(ES)
- 分析,展示(Kibana)
下載解壓

啟動

訪問測試

開發工具(之后的所有操作都在這里進行)

修改語言

ES核心概念
集群,節點,索引,類型,文檔,分片,映射是什么?
elasticSearch是面向文檔 一切都是json
| Mysql | ElasticSearch |
|---|---|
| 數據庫(database) | 索引(indices) |
| 表(tables) | 類型(types)【慢慢被棄用】 |
| 行(rows) | 文檔(documents) |
| 字段(columns)屬性 | 映射(fields) |
物理設計:elasticSearch在后台把每個索引划分成多個切片,每分分片可以在集群中的不同服務器上遷移
一個人就是一個集群,默認集群名稱就是elasticsearch

文檔 :索引的最小數據就是文檔(就是一條條數據)
類型 :字段類型映射(數據類型)
索引 :數據庫(一個elasticsearch索引是由多個Lucene倒排索引組成的)
分片:每個分片都是一個Lucene倒排索引
倒排索引:采用Lucene倒排索作為底層,這種結構用於快速的全文搜索,一個索引由文檔中所有不重復的列表構成,對於每一個詞,都有一個包含它的文檔列表。
4. 生態圈
5. ik分詞器
分詞:即把一段中文或者別的划分成一個個的關鍵詞,我們在搜索時會把我們自己的信息進行分詞,會把數據庫中或者索引庫中的數據進行分詞,然后進行一個匹配操作,默認的中文分詞是將每一個字看成一個詞,所以我們需要安裝IK分詞器來解決這個問題
ik分詞器兩種算法
- ik_smart,最少切分(不存在重復數據)
- ik_max_word,最細粒度划分(窮盡詞庫的可能--字典)
下載地址: https://github.com/medcl/elasticsearch-analysis-ik/releases
放入elasticsearch插件中

使用(查看不同的分詞器)

問題:字典中不存在的自定義詞,需要自己加入到分詞器字典中
ik分詞器增加自己的配置:

重啟es

查看

以后需要我們自己配置分詞只需要在自己定義的dic文件中進行即可
6. RestFul操作ElasticSearch
RestFul風格說明:一種軟件架構風格,只是提供了一組設計原則和約束條件,它主要用於客戶端與服務器交互類的軟件,基於這個風格設計的軟件可以更加簡潔,更有層次,更易於實現緩存等機制
基本Rest命令說明
| method | url地址 | 描述 |
|---|---|---|
| PUT | localhost:9200/索引名稱/類型名稱/文檔id | 創建文檔(指定文檔id) |
| POST | localhost:9200/索引名稱/類型名稱 | 創建文檔(隨機文檔id) |
| POST | localhost:9200/索引名稱/類型名稱/文檔id/_update | 修改文檔 |
| DELETE | localhost:9200/索引名稱/類型名稱/文檔id | 刪除文檔 |
| GET | localhost:9200/索引名稱/類型名稱/文檔id | 查詢文檔通過文檔id |
| POST | localhost:9200/索引名稱/類型名稱/_search | 查詢所有數據 |
基本測試
- 創建一個索引
PUT /索引名/類型名/文檔id
{
請求體
}

完成了自動增加索引,數據也成功的添加了

數據類型
字符串類型:text,keyword(不可分割)
數值類型:long,integer,short,byte,double,float,scaled
日期類型:date
布爾值:boolean
二進制:binary
-
指定字段類型
創建具體的索引規則

-
通過get請求獲取信息



如果自己的文檔字段沒有指定,那么es就會自動給我們配置字段類型

-
修改提交還是可以使用Put即可,進行覆蓋
版本號增加

使用POST修改

-
刪除索引
通過DELETE命令實現刪除

使用RestFul風格是es推薦使用的
7. 文檔的基本操作(重點)
-
基本操作

添加數據

獲取數據

更新數據
version代表這個數據被改動的次數(put如果不傳值就會被覆蓋)

推薦使用一下這種方式POST

查詢數據
簡單查詢:通過默認的映射規則,產生基本的查詢
GET /liuyunsan/user/1
GET /liuyunsan/user/_search?q=name:修仙

keyword只能整體搜索

匹配度(匹配度越高分值越高)

-
復雜操作(排序,分頁,高亮,模糊查詢,精准查詢)


hit:索引和文檔的信息,查詢的結果總數,然后就是查詢出來的具體文檔,數據中的東西就可以遍歷出來了,分數,我們可以通過score來判斷誰更加符合結果

結果過濾

排序(desc,asc)

分頁查詢

/search/{current}/{pagesize}
boolean值查詢(多條件精確查詢)and or not

must(相當於and,所有條件都要符合)
should(相當於or,其中一個符合即可)
must_not(相當於not,都不符合的即可)
過濾器filter 區間
查詢年齡大於10小於25的個數

gt:大於
gte:大於等於
lt:小於
lte:小於等於
匹配多個條件,通過權重來判別匹配的程度(多個條件空格隔開即可,只要滿足其中一個結果就會被查出)


精確查詢(term查詢是通過倒排索引指定的詞條精確查找的)
關於分詞:
term:直接查找精確的值(效率高)
match:會使用分詞器解析(先分析文檔,再通過分析的文檔進行查詢)
兩個類型
text:分詞器解析

keyword:不會被分詞器解析


多個值匹配的精確查詢

高亮查詢(搜索的結果會幫你自動增加一個html標簽)自定義樣式


- 匹配
- 按條件匹配
- 精確匹配
- 區間范圍匹配
- 匹配字段過濾
- 多條件查詢
- 高亮查詢
- 倒排索引
- mysql也可以做,但是效率很低
8. SpringBoot集成ElasticSearch(從原理分析)
文檔:https://www.elastic.co/guide/index.html



- 導入依賴
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.15.2</version>
</dependency>
- 初始化

- 分析類中方法

三個靜態內部類
- RestClientBuilderConfiguration.class
- RestHighLevelClientConfiguration.class
- RestClientSnifferConfiguration.class
核心類只有一個 - ElasticsearchRestClientConfigurations
- api測試
@SpringBootTest
class EsApiApplicationTests {
@Autowired
@Qualifier("restHighLevelClient")
private RestHighLevelClient client;
//索引創建
@Test
void contextLoads() throws IOException {
//1.創建索引的請求
CreateIndexRequest request = new CreateIndexRequest("liuyunsan_index");
//2.客戶端執行請求 IndexClient, 請求后獲得響應
CreateIndexResponse createIndexResponse = client.indices().create(request, RequestOptions.DEFAULT);
System.out.println(createIndexResponse);
}
//獲取索引,數據庫只能判斷存不存在
@Test
void testExist() throws IOException {
//1.創建索引的請求
GetIndexRequest request = new GetIndexRequest("liuyunsan_index");
//2.判斷索引是否存在
boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
System.out.println(exists);
}
//刪除索引
@Test
void deeteExist() throws IOException {
//1.創建索引的請求
DeleteIndexRequest request = new DeleteIndexRequest("liuyunsan_index");
//2.客戶端執行請求 IndexClient, 請求后獲得響應
AcknowledgedResponse delete = client.indices().delete(request, RequestOptions.DEFAULT);
System.out.println(delete.isAcknowledged());
}
//測試添加文檔
@Test
void insertDoc() throws IOException {
//創建對象
User user=new User("liuyunsan",3);
//創建請求
IndexRequest request = new IndexRequest("liuyunsan_index");
//規則 put /liuyunsan_index/_doc/1
request.id("1");
request.timeout(TimeValue.timeValueSeconds(1));//超時
//將我們的數據放入請求request json
request.source(JSON.toJSONString(user), XContentType.JSON);
//客戶端發送請求 獲取響應結果
IndexResponse index = client.index(request, RequestOptions.DEFAULT);
System.out.println(index.toString());
System.out.println(index.status()); //對應命令返回的狀態
}
//獲取文檔,判斷是否存在 GET /index/_doc/1
@Test
void getDoc() throws IOException {
GetRequest liuyunsan_index = new GetRequest("liuyunsan_index", "1");
liuyunsan_index.fetchSourceContext(new FetchSourceContext(false));//不獲取返回的_source的上下文
liuyunsan_index.storedFields("_none_");//排序字段
boolean exists = client.exists(liuyunsan_index, RequestOptions.DEFAULT);
System.out.println(exists);
}
//獲取文檔的信息
@Test
void getDocInformation() throws IOException {
GetRequest liuyunsan_index = new GetRequest("liuyunsan_index", "1");
GetResponse documentFields = client.get(liuyunsan_index, RequestOptions.DEFAULT);
System.out.println(documentFields.getSourceAsString());
System.out.println(documentFields); //返回的全部內容和命令是一樣的
}
//更新文檔記錄
@Test
void updateDocInformation() throws IOException {
UpdateRequest updateRequest = new UpdateRequest("liuyunsan_index", "1");
updateRequest.timeout("1s");
User user = new User("一剎流雲散", 77);
UpdateRequest doc = updateRequest.doc(JSON.toJSONString(user), XContentType.JSON);
UpdateResponse update = client.update(doc, RequestOptions.DEFAULT);
System.out.println(update);
}
//刪除文檔記錄
@Test
void deleteDocInformation() throws IOException {
DeleteRequest liuyunsan_index = new DeleteRequest("liuyunsan_index", "1");
liuyunsan_index.timeout("1s");
DeleteResponse delete = client.delete(liuyunsan_index, RequestOptions.DEFAULT);
System.out.println(delete);
}
//真實項目一般會批量插入數據
@Test
void InsertDocInformation() throws IOException {
BulkRequest bulkRequest = new BulkRequest();
bulkRequest.timeout("3s");
ArrayList<User> users = new ArrayList<>();
users.add(new User("流雲散1",3));
users.add(new User("流雲散2",4));
users.add(new User("流雲散3",5));
users.add(new User("流雲散4",6));
users.add(new User("流雲散5",7));
users.add(new User("流雲散6",8));
users.add(new User("流雲散7",9));
for (int i = 0; i <users.size() ; i++) {
//批量更新與刪除就在這里修改請求即可
//如果不設置id就會生成一個隨機id
bulkRequest.add(new IndexRequest("liuyunsan_index").id(""+(i+1)).source(JSON.toJSONString(users.get(i)),XContentType.JSON));
}
BulkResponse bulk = client.bulk(bulkRequest, RequestOptions.DEFAULT);
System.out.println(bulk);
System.out.println(bulk.hasFailures());//是否執行成功
}
//查詢
//SearchRequest 搜索請求
//SearchSourceBuilder 條件構造
// HighlightBuilder 構建高亮
//TermQueryBuilder 精確查詢
//MatchALLQueryBuilder 全部查詢
// xxxQueryBuilder 對應kibana中的命令
@Test
void QueryDocInformation() throws IOException {
SearchRequest liuyunsan_index = new SearchRequest("liuyunsan_index");
//構建搜索條件
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
//查詢條件,可以使用QueryBuilders快速構建
//term 精確匹配
//match 模糊匹配
TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("name", "流雲散3");
sourceBuilder.query(termQueryBuilder);
sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
//放入請求
liuyunsan_index.source(sourceBuilder);
SearchResponse search = client.search(liuyunsan_index,RequestOptions.DEFAULT);
System.out.println(JSON.toJSONString(search.getHits())); //從hit中取得查詢到的數據
for(SearchHit documentFields:search.getHits().getHits())
{
System.out.println(documentFields.getSourceAsMap());
}
}
}
9. 爬蟲爬取數據存入ElasticSearch(模擬全文檢索)
數據獲取:數據庫,消息隊列中獲取,都可以成為數據源,爬蟲
爬取數據(獲取請求返回的頁面信息,篩選出我們想要的數據就可以了)
jsoup包
搜索相關的都可以使用ElasticSearch(最好大數據量的情況下使用)
