全文检索工具elasticsearch:第一章:理论知识

本文涉及的产品
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
简介: 全文检索工具elasticsearch:第一章:理论知识

搜索



什么是搜索, 计算机根据用户输入的关键词进行匹配,从已有的数据库中摘录出相关的记录反馈给用户。


常见的全网搜索引擎,像百度、谷歌这样的。但是除此以外,搜索技术在垂直领域也有广泛的使用,比如淘宝、京东搜索商品,万芳、知网搜索期刊,csdn中搜索问题贴。也都是基于海量数据的搜索。


  如何处理搜索


   用传统关系性数据库


20190118201851619.png

弊端:  


1、 对于传统的关系性数据库对于关键词的查询,只能逐字逐行的匹配,性能非常差。


2、匹配方式不合理,比如搜索“小密手机” ,如果用like进行匹配, 根本匹配不到。但是考虑使用者的用户体验的话,除了完全匹配的记录,还应该显示一部分近似匹配的记录,至少应该匹配到“手机”。


  专业全文索引是怎么处理的


全文搜索引擎目前主流的索引技术就是倒排索引的方式。

  传统的保存数据的方式都是

     记录→单词

而倒排索引的保存数据的方式是

  单词→记录

例如

 搜索“红海行动”

但是数据库中保存的数据如图:

20190118201911968.png

那么搜索引擎是如何能将两者匹配上的呢?

基于分词技术构建倒排索引

首先每个记录保存数据时,都不会直接存入数据库。系统先会对数据进行分词,然后以倒排索引结构保存。如下:

20190118201921202.png

然后等到用户搜索的时候,会把搜索的关键词也进行分词,会把“红海行动”分词分成:红海和行动两个词。


这样的话,先用红海进行匹配,得到id=1和id=2的记录编号,再用行动匹配可以迅速定位id为1,3的记录。


那么全文索引通常,还会根据匹配程度进行打分,显然1号记录能匹配的次数更多。所以显示的时候以评分进行排序的话,1号记录会排到最前面。而2、3号记录也可以匹配到。


 全文检索工具elasticsearch


 lucene与elasticsearch


咱们之前讲的处理分词,构建倒排索引,等等,都是这个叫lucene的做的。那么能不能说这个lucene就是搜索引擎呢?


还不能。lucene只是一个提供全文搜索功能类库的核心工具包,而真正使用它还需要一个完善的服务框架搭建起来的应用。


好比lucene是类似于jdk,而搜索引擎软件就是tomcat 的。


目前市面上流行的搜索引擎软件,主流的就两款,elasticsearch和solr,这两款都是基于lucene的搭建的,可以独立部署启动的搜索引擎服务软件。由于内核相同,所以两者除了服务器安装、部署、管理、集群以外,对于数据的操作,修改、添加、保存、查询等等都十分类似。就好像都是支持sql语言的两种数据库软件。只要学会其中一个另一个很容易上手。


从实际企业使用情况来看,elasticSearch的市场份额逐步在取代solr,国内百度、京东、新浪都是基于elasticSearch实现的搜索功能。国外就更多了 像维基百科、GitHub、Stack Overflow等等也都是基于ES的


 elasticSearch的使用场景


  1. 为用户提供按关键字查询的全文搜索功能。
  2. 著名的ELK框架(ElasticSearch,Logstash,Kibana),实现企业海量日志的处理分析的解决方案。大数据领域的重要一份子。

 elasticSearch的安装


全文检索工具elasticsearch:第二章:安装配置


  elasticsearch的基本概念


cluster

整个elasticsearch 默认就是集群状态,整个集群是一份完整、互备的数据。

node

集群中的一个节点,一般只一个进程就是一个node

shard

分片,即使是一个节点中的数据也会通过hash算法,分成多个片存放,默认是5片。

index

相当于rdbms的database, 对于用户来说是一个逻辑数据库,虽然物理上会被分多个shard存放,也可能存放在多个node中。

type

类似于rdbms的table,但是与其说像table,其实更像面向对象中的class , 同一Json的格式的数据集合。

document

类似于rdbms的 row、面向对象里的object

field

相当于字段、属性


 利用kibana学习 elasticsearch restful api (DSL)


执行bin目录下的kibana程序:

cd /opt/kibana-5.6.4-linux-x86_64/bin

./kibana


   es中保存的数据结构


public class  Movie {


String id;


    String name;


    Double doubanScore;


    List<Actor> actorList;


}



public class Actor{


String id;


String name;


}


这两个对象如果放在关系型数据库保存,会被拆成2张表,但是elasticsearch是用一个json来表示一个document。


所以他保存到es中应该是:

{


 “id”:”1”,


 “name”:”operation red sea”,


 “doubanScore”:”8.5”,


 “actorList”:[  


{“id”:”1”,”name”:”zhangyi”},


{“id”:”2”,”name”:”haiqing”},


{“id”:”3”,”name”:”zhanghanyu”}


]


}


对数据的操作增删改查


查看es中有哪些索引

GET /_cat/indices?v


es 中会默认存在一个名为.kibana的索引

health status index   uuid                   pri rep docs.count docs.deleted store.size pri.store.size
yellow open   .kibana sBDZ-v6YQMWx9GaQOmSQQg   1   1          1            0      3.2kb          3.2kb


表头的含义


health

green(集群完整) yellow(单点正常、集群不完整) red(单点不正常)

status

是否能使用

index

索引名

uuid

索引统一编号         

pri

主节点几个

rep

从节点几个

docs.count

文档数

docs.deleted

文档被删了多少

store.size

整体占空间大小

pri.store.size

主节点占


增加一个索引

PUT /movie_index

{
  "acknowledged": true,
  "shards_acknowledged": true,
  "index": "movie_index"
}


删除一个索引

     ES 是不删除也不修改任何数据

DELETE /movie_index

{
  "acknowledged": true
}


新增文档 

格式 :PUT /index/type/id

PUT /movie_index/movie/1


{ "id":1,


 "name":"operation red sea",


 "doubanScore":8.5,


 "actorList":[  


{"id":1,"name":"zhang yi"},


{"id":2,"name":"hai qing"},


{"id":3,"name":"zhang han yu"}


]


}


PUT /movie_index/movie/2


{


 "id":2,


 "name":"operation meigong river",


 "doubanScore":8.0,


 "actorList":[  


{"id":3,"name":"zhang han yu"}


]


}



PUT /movie_index/movie/3


{


 "id":3,


 "name":"incident red sea",


 "doubanScore":5.0,


 "actorList":[  


{"id":4,"name":"zhang chen"}


]


}

20190118203637138.png

如果之前没建过index或者type,es 会自动创建。

 直接用id查找

GET movie_index/movie/1


 修改整体替换

和新增没有区别

PUT /movie_index/movie/3


{


 "id":"3",


 "name":"incident red sea",


 "doubanScore":"5.0",


 "actorList":[  


{"id":"1","name":"zhang chen"}


]


}

20190118203834262.png

修改—某个字段

POST movie_index/movie/3/_update

{

  "doc": {

    "doubanScore":"7.0"

  }

}


修改—某个字段和 修改整体替换二者选一,否则:

20190118204539341.png


删除一个document

DELETE movie_index/movie/3

{
  "found": true,
  "_index": "movie_index",
  "_type": "movie",
  "_id": "3",
  "_version": 18,
  "result": "deleted",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  }
}


搜索type全部数据

GET movie_index/movie/_search


结果

{


 "took": 2,    //耗费时间 毫秒


 "timed_out": false, //是否超时


 "_shards": {


   "total": 5,   //发送给全部5个分片


   "successful": 5,


   "skipped": 0,


   "failed": 0


 },


 "hits": {


   "total": 3,  //命中3条数据


   "max_score": 1,   //最大评分


   "hits": [  // 结果


     {


       "_index": "movie_index",


       "_type": "movie",


       "_id": 2,


       "_score": 1,


       "_source": {


         "id": "2",


         "name": "operation meigong river",


         "doubanScore": 8.0,


         "actorList": [


           {


             "id": "1",


             "name": "zhang han yu"


           }


         ]


       }


         。。。。。。。。


         。。。。。。。。


     }


按条件查询(全部)

GET movie_index/movie/_search

{

  "query":{

    "match_all": {}

  }

}


按分词查询 

GET movie_index/movie/_search

{

  "query":{

    "match": {"name":"red"}

  }

}


注意结果的评分

20190118205002353.png

按分词子属性查询 

GET movie_index/movie/_search

{

  "query":{

    "match": {"actorList.name":"zhang"}

  }

}

结果:

{
  "took": 2,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 2,
    "max_score": 1,
    "hits": [
      {
        "_index": "movie_index",
        "_type": "movie",
        "_id": "2",
        "_score": 1,
        "_source": {
          "id": 2,
          "name": "operation meigong river",
          "doubanScore": 8,
          "actorList": [
            {
              "id": 3,
              "name": "zhang han yu"
            }
          ]
        }
      },
      {
        "_index": "movie_index",
        "_type": "movie",
        "_id": "1",
        "_score": 1,
        "_source": {
          "id": 1,
          "name": "operation red sea",
          "doubanScore": 8.5,
          "actorList": [
            {
              "id": 1,
              "name": "zhang yi"
            },
            {
              "id": 2,
              "name": "hai qing"
            },
            {
              "id": 3,
              "name": "zhang han yu"
            }
          ]
        }
      }
    ]
  }
}


match phrase

GET movie_index/movie/_search

{

    "query":{

      "match_phrase": {"name":"operation red"}

    }

}

按短语查询,不再利用分词技术,直接用短语在原始数据中匹配

我就不发结果了,太长的博客也不好看。


 fuzzy查询

GET movie_index/movie/_search

{

    "query":{

      "fuzzy": {"name":"rad"}

    }

}

校正匹配分词,当一个单词都无法准确匹配,es通过一种算法对非常接近的单词也给与一定的评分,能够查询出来,但是消耗更多的性能。


过滤--查询后过滤


GET movie_index/movie/_search


{


   "query":{


     "match": {"name":"red"}


   },


   "post_filter":{


     "term": {


       "actorList.id": 3


     }


   }


}

————————————————

版权声明:本文为CSDN博主「我是廖志伟」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/java_wxid/article/details/86543331过滤--查询后过滤


GET movie_index/movie/_search


{


   "query":{


     "match": {"name":"red"}


   },


   "post_filter":{


     "term": {


       "actorList.id": 3


     }


   }


}


先查询后过滤效率慢,好比,我先从全国所有人中先过滤其他省份的留下广东的,再查询比先查询全国所有人再过滤广东的


过滤--查询前过滤(推荐)


GET movie_index/movie/_search


{


   "query":{


       "bool":{


         "filter":[ {"term": {  "actorList.id": "1"  }},


                    {"term": {  "actorList.id": "3"  }}


          ],


          "must":{"match":{"name":"red"}}


        }


   }


}


过滤--按范围过滤


GET movie_index/movie/_search


{


  "query": {


    "bool": {


      "filter": {


        "range": {


           "doubanScore": {"gte": 8}


        }


      }


    }


  }


}


关于范围操作符:

gt

大于

lt

小于

gte

大于等于

lte

小于等于


排序


GET movie_index/movie/_search


{


 "query":{


   "match": {"name":"red sea"}


 }


 , "sort": [


   {


     "doubanScore": {


       "order": "desc"


     }


   }


 ]


}


这个先按名称后按red sea排序


分页查询


GET movie_index/movie/_search


{


 "query": { "match_all": {} },


 "from": 1,


 "size": 1


}


指定查询的字段


GET movie_index/movie/_search


{


 "query": { "match_all": {} },


 "_source": ["name", "doubanScore"]


}


太多了,但我坚持,希望尽最大努力把我知道的全部写出来。


高亮


GET movie_index/movie/_search


{


   "query":{


     "match": {"name":"red sea"}


   },


   "highlight": {


     "fields": {"name":{} }


   }  


}


聚合


取出每个演员共参演了多少部电影


GET movie_index/movie/_search


{


 "aggs": {


   "groupby_actor": {


     "terms": {


       "field": "actorList.name.keyword"  


     }


   }


 }


}


每个演员参演电影的平均分是多少,并按评分排序


GET movie_index/movie/_search


{


 "aggs": {


   "groupby_actor_id": {


     "terms": {


       "field": "actorList.name.keyword" ,


       "order": {


         "avg_score": "desc"


         }


     },


     "aggs": {


       "avg_score":{


         "avg": {


           "field": "doubanScore"


         }


       }


      }


   }


 }


}


关于mapping的类型


之前说type可以理解为table,那每个字段的数据类型是如何定义的呢

查看看mapping

GET movie_index/_mapping/movie


{
  "movie_index": {
    "mappings": {
      "movie": {
        "properties": {
          "actorList": {
            "properties": {
              "id": {
                "type": "long"
              },
              "name": {
                "type": "text",
                "fields": {
                  "keyword": {
                    "type": "keyword",
                    "ignore_above": 256
                  }
                }
              }
            }
          },
          "doubanScore": {
            "type": "float"
          },
          "id": {
            "type": "long"
          },
          "name": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          }
        }
      }
    }
  }
}

实际上每个type中的字段是什么数据类型,由mapping定义。


但是如果没有设定mapping系统会自动,根据一条数据的格式来推断出应该的数据格式。


true/false → boolean

1020  →  long

20.1 → double

“2017-02-01” → date

“hello world” → text +keyword

默认只有text会进行分词,keyword是不会分词的字符串。


mapping除了自动定义,还可以手动定义,但是只能对新加的、没有数据的字段进行定义。一旦有了数据就无法再做修改了。


注意:虽然每个Field的数据放在不同的type下,但是同一个名字的Field在一个index下只能有一种mapping定义。


中文分词

elasticsearch本身自带的中文分词,就是单纯把中文一个字一个字的分开,根本没有词汇的概念。但是实际应用中,用户都是以词汇为条件,进行查询匹配的,如果能够把文章以词汇为单位切分开,那么与用户的查询条件能够更贴切的匹配上,查询速度也更加快速。


分词器下载网址:https://github.com/medcl/elasticsearch-analysis-ik


安装


下载好的zip包,请解压后放到 /usr/share/elasticsearch/plugins/


cp /opt/elasticsearch-analysis-ik-5.6.4.zip  elastic


unzip elastic


rm elastic


然后重启es


service elasticsearch stop


service elasticsearch start


测试使用


使用默认


GET movie_index/_analyze


{  


 "text": "我是中国人"


}


   请观察结果


使用分词器


GET movie_index/_analyze


{  "analyzer": "ik_smart",


 "text": "我是中国人"


}


请观察结果


  另外一个分词器


   ik_max_word


GET movie_index/_analyze


{  "analyzer": "ik_max_word",


 "text": "我是中国人"


}


请观察结果


能够看出不同的分词器,分词有明显的区别,所以以后定义一个type不能再使用默认的mapping了,要手工建立mapping, 因为要选择分词器。


基于中文分词搭建索引


1、建立mapping


PUT movie_chn


{


 "mappings": {


   "movie":{


     "properties": {


       "id":{


         "type": "long"


       },


       "name":{


         "type": "text"


         , "analyzer": "ik_smart"


       },


       "doubanScore":{


         "type": "double"


       },


       "actorList":{


         "properties": {


           "id":{


             "type":"long"


           },


           "name":{


             "type":"keyword"


           }


         }


       }


     }


   }


 }


}



插入数据


PUT /movie_chn/movie/1


{ "id":1,


 "name":"红海行动",


 "doubanScore":8.5,


 "actorList":[  


 {"id":1,"name":"张译"},


 {"id":2,"name":"海清"},


 {"id":3,"name":"张涵予"}


]


}


PUT /movie_chn/movie/2


{


 "id":2,


 "name":"湄公河行动",


 "doubanScore":8.0,


 "actorList":[  


{"id":3,"name":"张涵予"}


]


}



PUT /movie_chn/movie/3


{


 "id":3,


 "name":"红海事件",


 "doubanScore":5.0,


 "actorList":[  


{"id":4,"name":"张晨"}


]


}


查询测试


GET /movie_chn/movie/_search


{


 "query": {


   "match": {


     "name": "红海战役"


   }


 }


}



GET /movie_chn/movie/_search


{


 "query": {


   "term": {


     "actorList.name": "张译"


   }


 }


}


自定义词库


修改/usr/share/elasticsearch/plugins/ik/config/中的IKAnalyzer.cfg.xml


<?xml version="1.0" encoding="UTF-8"?>


<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">


<properties>


       <comment>IK Analyzer 扩展配置</comment>


       <!--用户可以在这里配置自己的扩展字典 -->


       <entry key="ext_dict"></entry>


        <!--用户可以在这里配置自己的扩展停止词字典-->


       <entry key="ext_stopwords"></entry>


       <!--用户可以在这里配置远程扩展字典 -->


        <entry key="remote_ext_dict">http://192.168.67.163/fenci/myword.txt</entry>


       <!--用户可以在这里配置远程扩展停止词字典-->


       <!-- <entry key="remote_ext_stopwords">words_location</entry> -->


</properties>


按照标红的路径利用nginx发布静态资源


在nginx.conf中配置


 server {


       listen  80;


       server_name  192.168.67.163;


       location /fenci/ {


          root es;


   }


  }



并且在/usr/local/nginx/下建/es/fenci/目录,目录下加myword.txt


myword.txt中编写关键词,每一行代表一个词。



然后重启es服务器,重启nginx。


在kibana中测试分词效果


更新完成后,es只会对新增的数据用新词分词。历史数据是不会重新分词的。如果想要历史数据重新分词。需要执行:


POST movies_index_chn/_update_by_query?conflicts=proceed


有点长了,分章节吧,第三章继续写。

相关实践学习
使用阿里云Elasticsearch体验信息检索加速
通过创建登录阿里云Elasticsearch集群,使用DataWorks将MySQL数据同步至Elasticsearch,体验多条件检索效果,简单展示数据同步和信息检索加速的过程和操作。
ElasticSearch 入门精讲
ElasticSearch是一个开源的、基于Lucene的、分布式、高扩展、高实时的搜索与数据分析引擎。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr(也是基于Lucene)。 ElasticSearch的实现原理主要分为以下几个步骤: 用户将数据提交到Elastic Search 数据库中 通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据 当用户搜索数据时候,再根据权重将结果排名、打分 将返回结果呈现给用户 Elasticsearch可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。
相关文章
|
2月前
|
JSON 自然语言处理 Java
ElasticSearch 实现分词全文检索 - 搜素关键字自动补全(Completion Suggest)
ElasticSearch 实现分词全文检索 - 搜素关键字自动补全(Completion Suggest)
55 1
|
2月前
|
自然语言处理 Java 关系型数据库
ElasticSearch 实现分词全文检索 - 聚合查询 cardinality
ElasticSearch 实现分词全文检索 - 聚合查询 cardinality
30 1
|
2月前
|
自然语言处理 Java 关系型数据库
ElasticSearch 实现分词全文检索 - SpringBoot 完整实现 Demo 附源码【完结篇】
ElasticSearch 实现分词全文检索 - SpringBoot 完整实现 Demo 附源码【完结篇】
31 0
|
2月前
|
存储 自然语言处理 Java
ElasticSearch 实现分词全文检索 - 经纬度定位商家距离查询
ElasticSearch 实现分词全文检索 - 经纬度定位商家距离查询
15 0
|
2月前
|
自然语言处理 Java
ElasticSearch 实现分词全文检索 - 高亮查询
ElasticSearch 实现分词全文检索 - 高亮查询
51 0
|
2月前
|
缓存 自然语言处理 Java
ElasticSearch 实现分词全文检索 - filter查询
ElasticSearch 实现分词全文检索 - filter查询
31 0
|
2月前
|
自然语言处理 Java
ElasticSearch 实现分词全文检索 - 复合查询
ElasticSearch 实现分词全文检索 - 复合查询
46 0
|
1月前
|
NoSQL 关系型数据库 Redis
mall在linux环境下的部署(基于Docker容器),Docker安装mysql、redis、nginx、rabbitmq、elasticsearch、logstash、kibana、mongo
mall在linux环境下的部署(基于Docker容器),docker安装mysql、redis、nginx、rabbitmq、elasticsearch、logstash、kibana、mongodb、minio详细教程,拉取镜像、运行容器
mall在linux环境下的部署(基于Docker容器),Docker安装mysql、redis、nginx、rabbitmq、elasticsearch、logstash、kibana、mongo
|
2月前
|
数据可视化 Docker 容器
一文教会你如何通过Docker安装elasticsearch和kibana 【详细过程+图解】
这篇文章提供了通过Docker安装Elasticsearch和Kibana的详细过程和图解,包括下载镜像、创建和启动容器、处理可能遇到的启动失败情况(如权限不足和配置文件错误)、测试Elasticsearch和Kibana的连接,以及解决空间不足的问题。文章还特别指出了配置文件中空格的重要性以及环境变量中字母大小写的问题。
一文教会你如何通过Docker安装elasticsearch和kibana 【详细过程+图解】
|
2月前
|
JSON 自然语言处理 数据库
Elasticsearch从入门到项目部署 安装 分词器 索引库操作
这篇文章详细介绍了Elasticsearch的基本概念、倒排索引原理、安装部署、IK分词器的使用,以及如何在Elasticsearch中进行索引库的CRUD操作,旨在帮助读者从入门到项目部署全面掌握Elasticsearch的使用。
下一篇
无影云桌面