一.ElasticSearch教程-全文检索&ES概述&ES安装&Kibana安装

1 全文检索

1.1 为什么需要全文检索

大型分布式的商城项目,例如京东,淘宝的关键字搜索框如何高效地检索数据?

如果使用数据库的模糊查询,像是like,缺点如下:
速度非常慢,因为LIKE是将数据从头到尾匹配,在大数据的情况下,匹配速度会非常久
需要匹配的数据库表、数据库数据众多

使用全文检索引擎:可以通过提前将数据库中要检索的数据,放入到全文搜索工具中,将所有数据按照一定的规则进行排序,再进搜索
优点:
速度快:按照一定的规则排序之后,无论用户搜索什么,我们都可以快速找到对应数据
可以实现搜索相似度高的数据排在前面
关键字的高亮,仔细观察我们的百度搜索、商城搜索,可以发现我们搜索的关键字是会有颜色标注的
只处理文本不处理语义:意思就是把相关搜索结果文章告诉你,而不是直接得到答案

全文检索引擎的优点:搜索速度快,可根据需求进行定制化配置

一.ElasticSearch教程-全文检索&ES概述&ES安装&Kibana安装_第1张图片

1.2 什么是全文搜索引擎

  • 数据的分类
    • 结构化数据:类似于MySql存储的数据,就是结构化数据,结构化数据搜索可以按照一定的规则去找,所以结构化数据搜索是最快的
    • 半结构化数据:类似于XML、JSON格式的数据,有一定结构的数据,搜索效率没有结构化数据高
    • 非结构化数据:类似于Word、PDF格式的数据,就是纯粹的文本数据,完全没有结构
  • 全文检索引擎:其实就是将无结构的数据,通过全文检索引擎变成有结构的数据,从而实现高效率搜索
    • 全文:针对所有文本,也就是我们存储到搜索服务器中的文本内容
    • 检索:就是搜索的意思
    • 引擎:可以认为是一个服务器,一个工具,我们可以使用这个工具达到我们想要的效果

1.3 常见的全文搜索引擎

  • Lucene:是搜索引擎的底层,常用的搜索引擎都是封装了Lucene,它是一个工具包
  • ElasticSearch:全文搜索服务器 ,封装了lucene并扩展,适用于中大型项目
  • Solr:全文检索服务器,仅次于ElasticSearch,封装了lucene并扩展,使用于中型项目(社区活跃度不及ElasticSearch,不推荐)

2 ES概述

2.1 为什么使用ElasticSearch(ES)

全文搜索领域,Lucene被认为是迄今为止最先进、性能最好的、功能最全的搜索引擎库

但是Lucene只是一个库,想要使用它,你必须使用Java来作为开发语言并将其直接集成到你的应用中,而且Lucene的配置及使用非常复杂,你需要深入了解检索的相关知识来理解它是如何工作的,所以我们需要使用Lucene的包装技术ElasticSearch

2.2 什么是ES

  • ES是一个分布式的全文搜索引擎,为了解决原生Lucene使用的不足,优化Lucene的调用方式,并实现了高可用的分布式集群的搜索方案,ES的索引库管理支持依然是基于Apache Lucene™的开源搜索引擎

  • ES使用Java开发,并使用Lucene作为其核心来实现索引创建和索引搜索的功能,但是它的目的是通过简单的 RESTful API来替换掉Lucene的复杂性,从而让全文搜索变得简单

  • 总的来说ElasticSearch简化了全文检索lucene的使用,同时增加了分布式的特性,使得构建大规模分布式全文检索变得非常容易 ,底层基于Luence,上手快。

添加一个文档:
PUT /shop/user/1
{
  "id":1,
  "name":"张三"
}

根据索引获取文档:
GET /shop/user/1

2.3 ES特点

  • 分布式的近实时文件存储:存入ES的数据,可以很快被搜索到,所以叫近实时,mysql就是实时文件存储,存入立马可以被查询到
  • 能在分布式项目/集群中使用,是分布式全文搜索引擎,每个字段都被索引并可被搜索,ES的数据在集群中的每个服务器上都可被搜索到
  • 处理PB级结构化或非结构化数据:可以处理的数据量非常大,因为1024TB=1PB
  • 简单的 RESTful API通信方式:可以通过API进行调用使用
  • 支持各种语言的客户端:只要是支持发送HTTP请求的语言ES都支持
  • 基于Lucene封装,操作简单

2.4 ES和Lucene的区别

  • Lucene只支持Java,ES支持多种语言
  • Lucene非分布式,ES支持分布式
  • Lucene非分布式的,索引目录只能在项目本地 , ES的索引库可以跨多个服务分片存储
  • Lucene使用非常复杂 , ES屏蔽了Lucene的使用细节,操作更方便
  • 单体/小项目使用Lucene/solr,大项目,分布式项目使用ES

2.5 ES使用案例

  • Github使用Elasticsearch搜索20TB的数据,包括13亿的文件和1300亿行的代码
  • Foursquare实时搜索5千万地点信息,Foursquare每天都用Elasticsearch做这样的事
  • Sony公司使用Elasticsearch 作为信息搜索引擎

2.6 其他搜索引擎

  • Solr-重量级对手
    • Apache Lucene项目的开源企业搜索平台。其主要功能包括全文检索、命中标示、分面搜索、动态聚类、数据库集成,以及富文本(如Word、PDF)的处理。Solr是高度可扩展的,并提供了分布式搜索和索引复制。Solr是最流行的企业级搜索引擎,Solr4 还增加了NoSQL支持
    • Solr和ES比较
      • Solr 利用 Zookeeper 进行分布式管理,而 Elasticsearch 自身带有分布式协调管理功能
      • Solr 支持更多格式的数据,而 Elasticsearch 仅支持json文件格式
      • Solr 官方提供的功能更多,而 Elasticsearch 本身更注重于核心功能,高级功能多有第三方插件提供
      • Solr 在传统的搜索应用中表现好于 Elasticsearch,但在处理实时搜索应用时效率明显低于 Elasticsearch
      • Solr 是传统搜索应用的有力解决方案,但Elasticsearch更适用于新兴的实时搜索应用
  • Katta
    • 基于 Lucene 的,支持分布式,可扩展,具有容错功能,准实时的搜索方案
    • 优点:开箱即用,可以与 Hadoop (大数据)配合实现分布式。具备扩展和容错机制
    • 缺点:只是搜索方案,建索引部分还是需要自己实现。在搜索功能上,只实现了最基本的需求。成功案例较少,项目的成熟度稍微差一些
  • HadoopContrib
    • 大数据相关的东西
    • Map/Reduce 模式(云计算)的,分布式建索引方案,可以跟 Katta 配合使用
    • 优点:分布式建索引,具备可扩展性
    • 缺点:只是建索引方案,不包括搜索实现。工作在批处理模式,对实时搜索的支持不佳

2.7 ES的优点

  1. 分布式架构:ES是一种基于Lucene的分布式全文搜索引擎,在数据存储和查询方面具有较强的并发处理能力和水平扩展能力。例如,在日志分析领域,使用ELK Stack(Elasticsearch、Logstash和Kibana)将日志收集、过滤、存储和可视化展现的整个流程,其中的Elasticsearch作为强大的搜索引擎支持海量日志的快速检索和分析。

  2. 实时搜索:ES支持实时查询,并且可以在毫秒级别内返回搜索结果,有效地支持监控应用程序、搜索引擎、电商应用、金融交易等需要快速反馈的场景。例如,在电商应用领域,使用ES来搜索商品可以实现实时展示用户感兴趣的商品信息,提高用户购物体验。

  3. 强大的搜索功能:ES拥有先进的搜索能力,可以支持全文检索、多字段匹配、模糊匹配、拼音转换、近似搜索、词项匹配等多种搜索方式,同时还支持聚合、分组、分页、排序等高级特性。例如,在社交网络应用中,可以使用ES来搜索用户、话题和帖子,实现高效的匹配和聚合。

  4. 易于使用:ES提供了简单易用的API和UI界面,支持多种编程语言的客户端,方便开发人员进行搜索和管理。同时ES还有许多插件和第三方工具,如Kibana、Beats等,能够进一步扩展ES的功能。例如,在安全分析领域,使用Elasticsearch Security插件可以扩展ES的用户认证和授权功能,提高系统的安全性。

  5. 大数据处理能力:ES支持海量数据的存储和处理,并且能够与Hadoop、Spark等大数据技术结合使用,处理大规模数据。例如,在广告推荐系统中,使用ES作为数据存储和查询的引擎,可以处理千万级别的用户和广告数据,从而实现更准确的推荐服务。

  6. 开源免费:ES是一款开源软件,采用Apache 2.0许可证,可以免费使用和修改,对于独立开发者和小型企业来说成本较低。例如,国内知名的拼音搜索引擎Pinyinjoe就采用了Elasticsearch,提供了开放的搜索接口。

综上所述,ES具有分布式、实时、强大的搜索功能、易于使用、大数据处理能力和开源免费等多种优点,成为了企业级全文搜索引擎的首选方案,被广泛应用于多个领域。

3 ES下载安装

  • ES的安装比较简单,只需要官方下载ES的运行包,然后启动ES服务即可。ES的使用主要是通过能够发起HTTP请求的终端来接入,比如Poster插件、CURL、kibana5等
  • ES服务只依赖于JDK,推荐使用JDK1.8+,本课程在window环境下,以ES6.8.6版本为例,下载对应的ZIP文件
  • 官网:https://www.elastic.co/downloads/elasticsearch,最新版本是8.X,不推荐下载使用
  • 安装:ES是绿色安装,解压即安装

一.ElasticSearch教程-全文检索&ES概述&ES安装&Kibana安装_第2张图片

3.1 启动

一.ElasticSearch教程-全文检索&ES概述&ES安装&Kibana安装_第3张图片
一.ElasticSearch教程-全文检索&ES概述&ES安装&Kibana安装_第4张图片
一.ElasticSearch教程-全文检索&ES概述&ES安装&Kibana安装_第5张图片

3.2 ES内存配置

  • ES默认占用内存是1G,我们可以调小一点,防止ES占用内存过大

一.ElasticSearch教程-全文检索&ES概述&ES安装&Kibana安装_第6张图片

4 Kibana:ES的可视化平台

  • Kibana:是为ES设计的开源分析和可视化平台,你可以使用 Kibana 来搜索、查看存储在ES索引中的数据并与之交互,你可以很容易实现高级的数据分析和可视化,以图表的形式展现出来
  • 总的来说就是帮助我们更加便捷的操作ES、展示ES的数据

4.1 Kibana安装

  • 官网:https://www.elastic.co/downloads/kibana
  • Kibana也是绿色安装,本次我们使用的是和ES一样的版本6.X,一般情况下都和使用的ES版本一致即可
  • 默认情况下双击Kibana.bat会连接本地ES:http://localhost:9200,进行使用,但是我们可以通过配置文件进行修改

一.ElasticSearch教程-全文检索&ES概述&ES安装&Kibana安装_第7张图片
一.ElasticSearch教程-全文检索&ES概述&ES安装&Kibana安装_第8张图片

4.2 Kibana测试

  • 浏览器访问:http://localhost:5601,Kibana的默认访问地址

一.ElasticSearch教程-全文检索&ES概述&ES安装&Kibana安装_第9张图片

4.3修改Kibana为中文界面

  • Kibana默认是英文界面,我们可以在配置中进行修改,修改后重启即可

一.ElasticSearch教程-全文检索&ES概述&ES安装&Kibana安装_第10张图片

4.4 ES基本概念

  • 查询上下文
    • 在ES查询后会返回一些信息,比如分页信息、结果信息、相关度分数等,这些都是通过查询上下文进行返回
  • 相关度分数
    • 默认情况下,ES根据相关性分数对结果进行排序,相关性分数是一个浮点型数字,通过过滤元数据字段_score返回,分数越高,代表搜索结果的相关性越大
  • 元数据
    • 从索引中查询出的结果可以称之为元数据,也就是我们搜索ES后得到的结果称为元数据
# 创建索引,可以先删除索引,再重新添加文档类型映射
DELETE shop

PUT /shop



PUT /shop/_doc/_mapping
{
  "_doc":{
    "properties": {
      "id":{
        "type": "long"
      },
      "name":{
        "type": "text",
        "analyzer": "ik_smart",
        "search_analyzer": "ik_smart"
      },
      "age":{
        "type": "integer"
      },
      "sex":{
        "type": "integer"
      }
    }
  }
}




GET /shop/_doc/_search


GET /shop/_doc/_search
{
  "query":{
    "bool":{
      "must": [{ 
        "match": {
         "name":"我在成都"
        }
      }
        
      ],
      "filter": [{
          "term": {
            "sex": {
              "value": "1"
            }
          }
        },{
          "range": {
            "age": {
              "gte": 1,
              "lte": 12
            }
          }
        }
      ]
      
    }
        
      
  }, 
  "from": 2,
  "size":2,
  "sort": [
      {
        "age": "desc"
      }
  ],
  "_source": ["name","age","sex"]
}
package com.alibaba.es;

import com.alibaba.utils.ESClientUtil;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequestBuilder;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.sort.SortOrder;
import org.junit.Test;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Stream;

public class EsTest {
    /*
     * ES的crud
     * */
    @Test
    public void testAdd() {
        TransportClient client = ESClientUtil.getClient();// 获取连接,这里的client就是java连接ES的客户端
        // 添加数据
        // client.prepareIndex("索引名","类型名","id").setSource("json格式的数据").get();
        IndexRequestBuilder indexRequestBuilder = client.prepareIndex("shop", "_doc");
        Map<String, Object> map = new HashMap<>();
        map.put("id", 2);
        map.put("name", "李思思");
        map.put("age", 16);
        map.put("sex", 0);
        IndexResponse indexResponse = indexRequestBuilder.setSource(map).get();
        System.out.println(indexResponse);

    }

    @Test
    public void testGet() {
        TransportClient client = ESClientUtil.getClient();// 获取连接,这里的client就是java连接ES的客户端
        // 查询数据
        // client.prepareGet("索引名","类型名","id").get();
        // client.prepareGet("索引名","类型名","id").setOperationThreaded(false).get();
        GetResponse documentFields = client.prepareGet("shop", "_doc", "9g4_vogBBfk9FP3Z9OLv").get();
        System.out.println(documentFields.getSourceAsString());


    }

    @Test
    public void testUpdate() {
        TransportClient client = ESClientUtil.getClient();// 获取连接,这里的client就是java连接ES的客户端
        // 修改数据
        // client.prepareUpdate("索引名","类型名","id").setDoc("json格式的数据").get();
        IndexRequestBuilder indexRequestBuilder = client.prepareIndex("shop", "_doc", "9g4_vogBBfk9FP3Z9OLv");
        Map<String, Object> map = new HashMap<>();
        map.put("name", "李二麻子");
        IndexResponse indexResponse = indexRequestBuilder.setSource(map).get();
        System.out.println(indexResponse);


    }

    @Test
    public void testDelete() {
        TransportClient client = ESClientUtil.getClient();// 获取连接,这里的client就是java连接ES的客户端
        // 删除数据
        // client.prepareDelete("索引名","类型名","id").get();
        DeleteResponse deleteResponse = client.prepareDelete("shop", "_doc", "9g4_vogBBfk9FP3Z9OLv").get();
        System.out.println(deleteResponse);


    }

    /*
    复杂查询
    条件
    - 查询_doc表
    - name包含:我在成都
    - age在1~12之间
    - sex=1
    - 每页大小2
    - 从2页开始查
    - 按照age倒序
     */
    @Test
    public void testQuery() {
        TransportClient client = ESClientUtil.getClient();// 获取连接,这里的client就是java连接ES的客户端
        // 复杂查询
        // client.prepareSearch("索引名").setTypes("类型名").setQuery(QueryBuilders.boolQuery().must(QueryBuilders.matchQuery("字段名","字段值"))).get();
        SearchRequestBuilder searchRequestBuilder = client.prepareSearch("shop").setTypes("_doc"); // 查询_doc表
        // 查询条件
        //  查询_doc表
        //     - name包含:我在成都
        //     - age在1~12之间
        //     - sex=1
        //     - 每页大小2
        //     - 从2页开始查
        // 按照age倒序
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        // 分页查询
        searchRequestBuilder.setFrom(2).setSize(2);
        // 排序, 按照age倒序
        searchRequestBuilder.addSort("age", SortOrder.DESC);
        // name包含:我在成都
        boolQueryBuilder.must(QueryBuilders.matchQuery("name", "我在成都"));

        // sex = 1, age在1~12之间
        boolQueryBuilder.filter(QueryBuilders.termQuery("sex", 1)).filter(QueryBuilders.rangeQuery("age").gte(1).lte(12));

        // 查询
        SearchRequestBuilder searchRequestBuilder1 = searchRequestBuilder.setQuery(boolQueryBuilder);
        // 将结果转换为map输出
        Stream<SearchHit> stream = Arrays.stream(searchRequestBuilder1.get().getHits().getHits());
        // 流转换为数组
        SearchHit[] searchHits = stream.toArray(SearchHit[]::new);
        System.out.println(Arrays.toString(searchHits));
       // System.out.println(searchRequestBuilder1.get().getHits().getHits());

    }
    @Test
    public void testGenData(){
        TransportClient client = ESClientUtil.getClient();
        // for循环生成数据
        IndexRequestBuilder indexRequestBuilder = client.prepareIndex("shop", "_doc");
        Map<String, Object> map = new HashMap<>();
        for (int i = 0; i < 100; i++) {
            map.put("id", i);
            map.put("name", i%2==0?"李思思"+i:"我在成都");
            map.put("age", i);
            map.put("sex", i%2==0?0:1);
            indexRequestBuilder.setSource(map).get();
            // 清空map数据
            map.clear();
        }
    }

}

{
  "took" : 20,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 6,
    "max_score" : null,
    "hits" : [
      {
        "_index" : "shop",
        "_type" : "_doc",
        "_id" : "_g5KvogBBfk9FP3Zo-JB",
        "_score" : null,
        "_source" : {
          "sex" : 1,
          "name" : "我在成都",
          "age" : 7
        },
        "sort" : [
          7
        ]
      },
      {
        "_index" : "shop",
        "_type" : "_doc",
        "_id" : "_A5KvogBBfk9FP3Zo-I2",
        "_score" : null,
        "_source" : {
          "sex" : 1,
          "name" : "我在成都",
          "age" : 5
        },
        "sort" : [
          5
        ]
      }
    ]
  }
}

这个信息是Elasticsearch查询操作的返回结果,主要包括以下几个部分:

took:该查询操作耗时,单位为毫秒。

timed_out:查询操作是否超时。

_shards:查询操作在集群中涉及到的分片信息,包括:

a) total:涉及到的总分片数。

b) successful:查询成功的分片数。

c) skipped:跳过的分片数。

d) failed:查询失败的分片数。

hits:查询结果,包括:

a) total:符合查询条件的文档数量。

b) max_score:最高得分。

c) hits:命中的文档详细信息,包括该文档所在的索引、类型、ID等信息。

 - _index:文档所在的索引名称。
 
 - _type:文档类型。
 
 - _id:文档ID。
 
 - _score:文档得分。 
 
 - _source:文档内容。
 
 - sort:排序方式和依据。

 例如,上述结果中返回的6个命中文档,其中两个文档的相关信息包含有 “sex”、“name”、“age”三个字段。同时使用对“age”字段进行排序,第一个文档的“age”字段值为7,第二个文档的“age”字段值为5。





  • DSL:数据查询规范
    • 在MySql中查询语句叫做查询SQL,例如我们的SELECT,在Elasticsearch中查询语句叫做DSL,Elasticsearch基于JSON提供完整的查询DSL来定义查询
  • NearRealtime【NRT】
    • 近实时:表示从写入数据到数据可以被搜索到有一个小延迟,大概1秒,基于ES执行搜索和分析可以达到秒级
  • Index:索引
    • 在ES中索引就相当于是一个数据库,我们可以类比一下MySql,我们使用MySql第一步就是要创建数据库,那么在ES中第一步就是要创建索引
    • 创建一个索引:PUT http://localhost:9200/索引名称
    • 删除一个索引:DELETE http://localhost:9200/索引名称
    • 查询一个索引:GET http://localhost:9200/索引名称
  • Type:类型
    • 在ES中类型就相当于是一张数据库表,我们可以类比一下MySql,我们在MySql中创建好了数据库,那么必定要创建数据库表,在ES中叫做类型,但是在ES7之后会慢慢弃用类型,也就是不需要创建类型,我们目前在ES6.X中还是需要的
  • Document:文档,ES其实就是面向文档的
    • 在ES中文档就是最小的存储数据单位了,我们可以类比一下MySql,以前是在数据库/表/下存储一条数据,那么在ES中我们存储一条数据,叫做存储一个文档,在Index/Type/下存储一个Document
  • field:字段
    • 表示Document中的某个字段,叫做field
  • 文档ID:代表一个Document数据的唯一ID
    • 类似于MySql中一条数据的主键ID

Relational DB ElasticSearch
数据库 索引-Index
类型-Type
文档-Document
字段 字段-fieId
SQL语句 DSL语句
主键ID 文档ID

一.ElasticSearch教程-全文检索&ES概述&ES安装&Kibana安装_第11张图片
喜欢的话请给我点个赞再走吧,你的鼓励是我最大的动力!

你可能感兴趣的:(全文检索,elasticsearch,搜索引擎)