ElasticSearch全文檢索


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. 安裝

  1. 安裝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

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


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

重啟es服務查看head

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

這個head就當作是一個數據展示工具,我們后面所有的查詢可以在kabana做

  1. 安裝kibana(可視化平台)
    ELK關系
  2. 收集清洗數據(Loastash)
  3. 搜索,存儲(ES)
  4. 分析,展示(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分詞器增加自己的配置:

重啟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 查詢所有數據

基本測試

  1. 創建一個索引
    PUT /索引名/類型名/文檔id
    {
    請求體
    }


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

數據類型
字符串類型:text,keyword(不可分割)
數值類型:long,integer,short,byte,double,float,scaled
日期類型:date
布爾值:boolean
二進制:binary

  1. 指定字段類型
    創建具體的索引規則

  2. 通過get請求獲取信息



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

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

    使用POST修改

  4. 刪除索引
    通過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


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

  1. 分析類中方法

    三個靜態內部類
  • RestClientBuilderConfiguration.class
  • RestHighLevelClientConfiguration.class
  • RestClientSnifferConfiguration.class
    核心類只有一個
  • ElasticsearchRestClientConfigurations
  1. 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(最好大數據量的情況下使用)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM