zoukankan      html  css  js  c++  java
  • ES-基本原理及架构

    一、全文检索与ES

    (一)全文检索

      数据可以分为结构化数据和非结构化数据,比如说我们常用的sql语句就都是操作结构化数据,邮件等信息都是非结构化数据;

        对于结构化数据的查询可以使用sql语句进行查询,速度较快;

        对于非结构化数据的查询可以把非结构化数据变成结构化数据:先根据空格进行字符串拆分,得到一个基础的单词列表。需要去掉标点符号、转换大小写、去除停用词、重复的单词只记录一次,就得到了一个最终的单词列表。然后基于单词列表创建一个索引。查询时直接查询索引,找到关键词后根据关键词和文档的对应关系,找到文档列表。这个过程就是全文检索的过程。

      全文检索的场景有:搜索引擎、站内搜索、系统文件搜索

      全文检索技术有:

        Lucene:使用该技术需要对Lucene的API和底层架构非常了解,而且需要编写大量的JAVA代码

        Solr:使用JAVA实现一个web应用,可以使用rest方式的http请求,进程远程API调用

        ElasticSearch(ES):可以使用rest方式的http请求,进行远程API调用

      全文检索可以分为两大步骤:创建索引和搜索索引

        

        1、创建索引:

          1)获得原始文档

            原始文档就是待搜索的文档。
              搜索引擎:原始文档就是整个互联网的网页
              电商搜索:数据库中的商品数据
              站内搜索:微博搜索,微博的数据。
            如何获得原始文档:
              搜索引擎:使用爬虫程序
              电商搜索:使用jdbc查询数据库
              站内搜索:数据库中的数据
          2)需要对应每个原始文档创建一个Document对象
            Document对象是对原始文档的封装,需要使用Field对象保存原始文档的属性。例如:描述一个文件,需要有文件名称、文件的内容、文件的路径、文件的大小……
            Field:叫做字段或者域。field由两部分组成:名称和内容
            一个Document中可以有多个Field,不同的Document中可以有不同的Field。
          3)分析文档
            field中包含文件的相关属性,其中有些field是需要分词的。
            对需要分词的field的内容进行分词处理:
              1)字符串拆分
              2)去除标点符号
              3)转换大小写
              4)去除停用词
            最终得到一个单词列表。单词列表中每个单词需要封装成一个Term对象。
              term中包含两部分内容:term所在的field的名称关键词本身
            基于Term创建索引。

            注意:不是所有的field都需要分词
          4)创建索引
            基于上一步得到的单词列表创建索引,然后把索引和文档以及关键词和文档的对应关系保存到磁盘。
            索引库中包含的内容:索引、文档和索引与文档的对应关系

        2、搜索索引:

          1)用户交互接口:接收到用户输入的查询内容。

          2)把查询内容封装:封装成一个Query对象,其中包含要查询的内容以及要查询的field。
          3)根据关键词到索引上查询:迅速的定位到一个关键词,根据关键词和文档对应关系找到文档列表。
          4)根据文档的id列表取文档对象:得到一个文档列表,把文档列表展示给用户。

      索引库结构:索引库分为索引域和文档域,索引域里面存储的是term字典和文档的倒排索引,文档域存储的就是document。

              

    (二)ElasticSearch

      ElasticSearch是一款开源的高扩展分布式全文检索引擎。其是使用JAVA开发并使用Lucene作为核心来实现所有索引和搜索功能的。

        ES与Lucene对比:ES通过简单的Restful API来隐藏Lucene的复杂性,从而让全文检索变得简单。

        ES与Solr对比:Solr是通过ZK进行分布式管理的,而ES自身带的有分布式协调管理功能;Solr支持更多格式的数据,ES只支持Json格式的数据;Solr在传统搜索应用中表现好于ES,但是在处理实时搜索应用时效率明显低于ES,因为Solr创建索引时,会产生IO阻塞。

    二、ES概念与架构

    (一)概念

      ES不仅仅是存储,还会索引整个文档的内容让其可以进行搜索,在ES中,可以对文档进行索引、搜索、排序、过滤等操作。

      ES的概念有索引index、类型type、文档document、字段field和映射mapping

      1、索引index

        索引可以看作是MySQL中的数据库,一套数据可以使用一套索引。

        一个索引由一个名字来标识,名字必须全部是小写字母,当我们对这个索引中文档进行索引、搜索、更新和删除的时候,都需要使用这个名字。

      2、类型type

        类型类似与MySQL中的表,在一个索引中可以创建多个type。这个在es7及以后已经被废弃,只有_doc。

      3、文档document

        文档类似MySQL中的一条数据,存储的是具体的数据,存储格式为Json

      4、字段field

        相当于MySQL中的字段。

      5、映射mapping

        mapping对处理数据方式和规则做的一些限制,如某个字段的数据类型、默认值、分析器、是否被索引等

    (二)架构

        

       ES的架构总体如上图所示,从下到上分为网关、搜索引擎、四大组件、自动发现、通信和Restful API

      1、Gateway网关

        其作用是用来对数据进行持久化以及ES重启后重新恢复数据。

        es支持多种类型的gateway,有本地文件系统、分布式文件系统、Hadoop的HDFS等。

        其存储的信息包括索引信息、集群信息、mapping等

      2、districted lucene directory搜索引擎

        Gateway上层就是Lucene的分布式检索框架。

        ES是分布式的搜索引擎,虽然底层用的是Lucene,但是需要在每个节点上都运行Lucene进行相应的索引、查询、更新等操作,所以需要做成一个分布式的运行框架来满足业务需要。

      3、四大组件模块

        districted lucene directory之上就是ES的四大模块。

        Index Model:索引模块,对数据建立索引(通常是建立倒排索引)

        Seacher Model:搜索模块,就是对数据进行查询搜索

        Mapping Model:是数据映射与解析模块,数据的每个字段可以根据建立的表结构通过mapping进行映射解析;如果没有建立表结构,那么ES会根据数据类型来推测数据结构,并自动生成一个mapping,然后根据mapping进行解析

        River Model:在es2.0之后被取消了,表示可以使用插件处理。例如可以通过一些自定义脚本将传统数据库的数据实时同步到es中。

      4、自动发现Discovery Script

        es集群中各个节点通过discovery相互发现的,默认使用的是Zen。es是一个基于p2p的系统,他先通过广播寻找存在的节点,再通过多播协议来进行节点之间的通信,同时也支持点对点的交互。

        es还可以支持多种script脚本语言,例如mvel、js、python等。

      5、通信(Transport)

        代表es内部节点或集群与客户的交互方式,默认内部使用tcp协议进行交互,同时其还支持http协议,thrift、servlet、memcached、zeroMQ等通信协议。

        节点间通信端口默认9300-9400

      6、Restful接口

        最上层就是ES暴漏给我们的访问接口。 

    三、Restful访问ES

      使用Restful访问ES的方式:curl X<VERB> <PROTOCOL>://<HOST>:<PORT>/<PATH>?<QUERY_STRING>d <BOD

      其中VERB是请求方式(post、get....),PROTOCOL是协议(http、https......),HOST和PORT是es的ip和端口,PATH是API的终端路径,QUERY_STRING表示任何可选的查询字符串参数(例如@pertty将格式化的输出JSON格式),BODY是一个Json格式的请求体。

      1、创建索引和mapping映射(PUT  ip:9200/test)

    {
        "settings":{
            "index":{
                "number_of_shards":"5",
                "number_of_replicas":"1"
            }
        },
        "mappings":{
            "_doc":{
                "properties":{
                    "orderId":{
                        "type":"long",
                        "store":true,
                        "index":true
                    },
                    "orderName":{
                        "type":"text",
                        "store":true,
                        "index":true,
                        "analyzer":"standard"
                    },
                    "content":{
                        "type":"text",
                        "store":true,
                        "index":true,
                        "analyzer":"standard"
                    }
                }
            }
        }
    }

        也可以先设置索引,然后再设置mapping,设置mapping的路径:post  ip:9200/test/_doc/_mapping,参数与上面设置mapping的参数一样

    {
        "_doc":{
            "properties":{
                "orderId":{
                    "type":"long",
                    "store":true
                },
                "orderName":{
                    "type":"text",
                    "store":true,
                    "index":true,
                    "analyzer":"standard"
                },
                "content":{
                    "type":"text",
                    "store":true,
                    "index":true,
                    "analyzer":"standard"
                }
            }
        }
    }

        这里需要特殊说明一下,如果是es5及以前的版本,type可以随意定义,如果是es6,一个索引库中只能有一个type,如果是es7,一个索引库只能有一个type,且必须为“_doc”,其实Lucene是没有type这个概念的。

        对field属性:

          type:数据类型,如果是text,就一定会分词,如果是keyword,就不会分词

          store:是否存储原始数据,取决于是否要展示给用户看,但是不影响分词和索引

          index:是否要把当前field的内容添加到索引中,如果分词,就一定要索引,不分词也可以索引(例如身份证号或订单号)

          analyzer:具体的分词器,如果不写,则使用默认分词器

      2、删除索引

        直接使用:delete  ip:9200/test

      3、document处理

        对于文档的操作,都是:ip:9200/test/_doc/123(其中test为index,_doc为type,123为document的id),post请求表示增改操作,delete请求表示删除操作,get请求表示查询操作。其中只有post请求需要传递参数,也就是设置document的参数。

    {"orderId":123,"orderName":"123的测试订单号","content":"修改随便写一个进行测试"}

    四、查询表达式(Query DSL)

      1、查询全部

        请求地址:post  ip:9200/_search  查询可以添加索引或type进行查询:ip:9200/test/_doc/123

        请求参数:{"query":{"match_all":{}}}

      2、term查询    

        请求地址:post  ip:9200/test/_doc/_search

        请求参数:{"query":{"term":{"orderName":"123"}}}

          

      3、queryString查询

        请求地址:post  ip:9200/test/article/_search

        请求参数:{"query":{"query_string":{"default_field":"orderName","query":"123"}}}

      4、multi_match查询

        请求地址与上面一样,参数可以设置多个field进行查询:{"query":{"multi_match":{"query":"123","fields":["orderId", "orderName"]}}}

      5、bool查询

        布尔过滤器,其是一个符合过滤器,可以结果多个其他过滤器作为参数,并将这些过滤器组合成各式各样的布尔组合。

    {
        "bool":{
            "must":[],
            "should":[],
            "must_not":[],
            "filter":[]
        }
    }

        如上所示,一个布尔查询由must、should、must_not、filter四部分组成。

          must:必须为真,才会被匹配到

          should:查询列表中,只要有一个为真,就会被匹配到

          must_not:所有必须都不为真,才会被匹配到

          filter:对数据进行过滤,filter可以是多个

        以下是示例:

    {
        "query":{
            "bool":{
                "must":{
                    "query_string":{
                        "query":"李四",
                        "default_field":"name"
                    }
                },
                "should":{
                    "term":{
                        "address":"上海"
                    }
                },
                "filter":{
                    "query_string":{
                        "query":"",
                        "default_field":"sex"
                    }
                }
            }
        }
    }

    五、IK分词器和ElasticScher集成使用

    (一)使用标准分词器存在的问题  

      在查询数据时,在orderName中使用123就可以查询成功,但是使用”测试“去查询,就查询不到数据。这是因为在创建索引的时候,使用了标准分词器导致。

              

       可以使用:post  ip:9200/_analyze查看分词结果,如下图所示,可以看到,中文都被分成了一个一个汉字。

            

     (二)使用IK分词器

      安装IK分词器,安装地址:https://github.com/medcl/elasticsearch-analysis-ik/releases,这里需要注意一样,ES的版本要和IK分词器的版本对应,如果不对应,ES启动不起来。

    ./elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.2.4/elasticsearch-analysis-ik-6.2.4.zip

      版本不一致启动出现的异常信息

          

      访问IK分词器查看分词效果:post  ip:9200/_analyze,里面只需要传入analyzer和text,其中text为测试分词的文本,analyzer在IK分词器中有ik_smart和ik_max_word两种,分别是最少切分和最细力度切分。

           

       然后使用IK分词器创建索引:"analyzer":"ik_max_word",然后用中文词组搜索,就可以搜索到了。

          

    ------------------------------------------------------------------
    -----------------------------------------------------------
    ---------------------------------------------
    朦胧的夜 留笔~~
  • 相关阅读:
    从头到尾彻底解析Hash表算法
    postgres模糊匹配大杀器
    postgres数据库表空间收缩之pg_squeeze,pg_repack
    pgcli安装
    pg_waldump的使用
    数据库表空间收缩之pg_squeeze,pg_repack
    数据库fillfactor
    pgbouncer连接池
    mysql-选择使用Repeatable read的原因
    postgresql-锁相关
  • 原文地址:https://www.cnblogs.com/liconglong/p/15010606.html
Copyright © 2011-2022 走看看