赞
踩
Elasticsearch是一个搜索引擎,它底层是基于Lucene来实现的。
Lucene是一个Java库,它存在着一定的问题,如果项目的开发语言不是Java,那么是无法使用 Lucene;Lucene底层设计非常的复杂,需要深入的了解搜索相关的知识,才能用好它。
Elaticsearch它是完全基于Restful风格的API来使用,那么就不在局限于任何一门语言,都可以直接调用接口即可实现搜索服务。
**
分词:
**分词就是将一句话或者一段话,按照某个语义拆分为一个个的字或者词的过程。例如:
中华人民共和国
中华 华人 人民 共和国
前向索引在数据库领域用的很多,例如 MySQL的全文检索。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6L89unqV-1678946462776)(images/前向索引.jpg)]
搜索引擎中都是使用这种方式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iR9NMoeR-1678946462778)(images/倒排索引.jpg)]
前向索引,每个文档都有一个文档的编号,每个文档的编号对应着该文档的分词信息,用户在搜索匹配的时候,根据文档编号找到该文档对应的分词,去进行分词的匹配,如果有匹配的分词,那么该文档就在最终的结果集中,所以它查询的效率会很低,但是其分词构建索引过程较快,因为每个文档的分词都是独立的。
倒排索引,文档在写入搜索引擎的时候,对文档进行分词,将字典中已经存在的分词直接与文档进行映射,没有的分词,先添加到字典中,然后再映射。用户在搜索匹配的时候,直接到分词字典中去匹配,匹配到之后,将映射到该分词的文档提取出来,这种方式查询效率高,可以作相关性算分。
Elasticsearch是整个 elastic 产品栈的核心,数据的存储、分词、搜索都是通过 Elasticsearch来完成。
通过 docker安装,直接执行如下命令即可:
docker run -d -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.8.1
验证ES是否安装成功,在浏览器输入:http://ip:9200
Kibana是ES的可视化操作界面,安装方式如下所示:
docker run -d -p 5601:5601 -e ELASTICSEARCH_HOSTS=http://192.168.24.129:9200 kibana:7.8.1
验证Kibana是否安装成功,在浏览器输入: http://ip:5601
要进入到logstash的bin目录下,打开dos命令行,导入数据使用如下的命令:
logstash.bat -f D:/logstash/logstash-7.8.1/config/logstash.conf
logstash的内容如下所示:
input { file { path => "D:/logstash/logstash-7.8.1/movies.csv" start_position => "beginning" sincedb_path => "D:/logstash/logstash-7.8.1/db_path.log" } } filter { csv { separator => "," columns => ["id","content","genre"] } mutate { split => { "genre" => "|" } remove_field => ["path", "host","@timestamp","message"] } mutate { split => ["content", "("] add_field => { "title" => "%{[content][0]}"} add_field => { "year" => "%{[content][1]}"} } mutate { convert => { "year" => "integer" } strip => ["title"] remove_field => ["path", "host","@timestamp","message","content"] } } output { elasticsearch { hosts => "http://192.168.24.129:9200" index => "movies" document_id => "%{id}" } stdout {} }
我们类比 RDBMDS 来熟悉ES的一些基本概念:
RDBMS | Elasticsearch |
---|---|
数据库 | 索引 |
表 | type(在ES7之后,一个索引中只有一个type,叫做 _doc ) |
记录 | 文档(一个JSON对象) |
字段 | 属性 |
schema | mapping |
索引
在ES中三层含义:
- 索引,数据集;
- 索引,将数据写入到ES的过程叫做索引。
- 倒排索引。
查看所有的索引
// 查看所有的索引
GET _cat/indices
添加数据
// 简单的添加数据, 如果没有指定id,
// 那么ES会自动的生成一个id
POST user/_doc
{
"firstname": "Elon",
"lastname": "Musk"
}
指定id添加数据
// 指定id添加数据, 如果存在id相同的数据,
// 会直接覆盖原本的数据
POST user/_doc/1
{
"id": 1,
"firstname": "Pony",
"lastname": "Ma"
}
添加数据,如果存在就报错
// 添加数据,如果没有对应的id的数据就添加,
// 如果存在这种数据,就报错
POST user/_create/2
{
"id": 2,
"firstname": "Will",
"lastname": "Smith"
}
更新文档的结构
// 更新数据
POST user/_update/1
{
"doc": {
"firstname": "Kobe",
"lastname": "Bryant"
}
}
删除数据
// 删除数据
DELETE user/_doc/2
根据id查询数据
// 根据id查询
GET user/_doc/1
查看部分数据
// 查看部分数据
GET user/_search
查看数据总量
GET movies/_count
查询电影名字中包含有 seconds 的所有的电影
GET movies/_search
{
"query": {
"match": {
"title": "seconds"
}
}
}
查询电影的名字中包含有 beautiful 或者 mind所有的电影
GET movies/_search
{
"query": {
"match": {
"title": "beautiful mind"
}
}
}
查询电影的名字中包含有 beautiful 和 mind所有的电影
GET movies/_search
{
"query": {
"match": {
"title": {
"query": "mind beautiful",
"operator": "and"
}
}
}
}
查询电影的名字中包含有 "beautiful mind"这个短语的所有的电影
GET movies/_search
{
"query": {
"match_phrase": {
"title": "beautiful mind"
}
}
}
如果某个字段的数据是 keyword 类型,就是做等值比较, 最好使用 term查询(term是标准的比较)
// 查看某个属性的数据类型,就是查看其mapping信息
GET kibana_sample_data_flights/_mapping
GET kibana_sample_data_flights/_search
{
"query": {
"term": {
"Carrier": {
"value": "ES-Air"
}
}
}
}
查询电影在 [2000, 2002] 年上映的所有的电影
GET movies/_search
{
"query": {
"range": {
"year": {
"gte": 2000,
"lte": 2002
}
}
},
"from": 0,
"size": 3
}
查询电影的名字中包含有 beautiful 或者 mind,而且上映时间在 [2000, 2003] 所有的电影,多条件查询的结构如下所示:
{
"query": {
"bool": {
"must": [
]
}
}
}
GET movies/_search { "query": { "bool": { "must": [ { "match": { "title": "beautiful mind" } }, { "range": { "year": { "gte": 2000, "lte": 2003 } } } ] } } }
查询电影的名字和类型中包含有 Romance 所有的电影
GET movies/_search
{
"query": {
"multi_match": {
"query": "Romance",
"fields": ["title", "genre"]
}
}
}
查询电影名字中包含有 seconds 所有的电影,但是只查询id和title着两个属性的内容
GET movies/_search
{
"_source": ["id", "title"],
"query": {
"match": {
"title": "seconds"
}
}
}
查询电影名字中包含有 seconds 所有的电影,属性都不看
GET movies/_search
{
"_source": false,
"query": {
"match": {
"title": "seconds"
}
}
}
前缀匹配是一个网站中使用频率非常高的一个功能,而且在添加和删除字符的时候都会向服务器端发送请求,对服务器和ES都是一个挑战,所以ES针对这种前缀匹配,专门设计了一个数据类型
completion
。如果某个属性的数据类型是completion
,只能进行前缀匹配,并且ES会将查询的数据放到缓存中,如果接着有其他用户进行相同的前缀匹配的时候,会直接从内存中查找。 ES中一旦某个索引中有数据了,我们是不能调整它的 mapping 信息,所以在ES中要向指定某个属性的数据类型的时候,需要先设定mapping.
- 预先构思好索引中要存放什么数据,说白了就是有哪些属性
- 利用ES本身的能力(写入数据的时候,会自动创建mapping),写入一个样例数据,让ES帮我们创建好mapping.
- 查询mapping,按照我们的需求做出适当的调整
// 查看索引的mapping信息
GET movies/_mapping
- 将之前的索引删掉,将修改之后的mapping添加到ES中。
// 删除索引 DELETE movies // 添加mapping信息 PUT movies { "mappings" : { "properties" : { "@version" : { "type" : "text", "fields" : { "keyword" : { "type" : "keyword", "ignore_above" : 256 } } }, "genre" : { "type" : "text", "fields" : { "keyword" : { "type" : "keyword", "ignore_above" : 256 } } }, "id" : { "type" : "text", "fields" : { "keyword" : { "type" : "keyword", "ignore_above" : 256 } } }, "title" : { "type" : "completion" }, "year" : { "type" : "long" } } } }
- 导入正规数据
- 验证前缀匹配
GET movies/_search
{
"_source": false,
"suggest": {
"title_suggest": {
"prefix": "beau",
"completion": {
"field": "title",
"size": 10
}
}
}
}
Analysis是分词,它内部是通过分词器(analyzer)来完成,
数据在写入到ES的过程会对文本内容进行分词,用户在搜索的时候,也会对用户搜索的内容再进行分词
。 Analyzer在整个分词的过程中,经过三个流程:
- character filter,将内容的信息进行过滤
- tokenizer,将全文本进行分词处理
- token filter,去掉分词之后的停用词,然后将其他内容转小写
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-suLcQp15-1678946462779)(images/Analyzer.jpg)]
ES内置的分词器只能对英文进行分词处理,ES内置的分词器有:
- whitespace
- stop
- standard
- simple
验证某个分词器的分词效果:
GET _analyze
{
"analyzer": "stop",
"text": " Use event filter to 89 drop-events earlier than the specified timestamp in timestamp startup mode"
}
IK是目前社区用的最多一款中文分词器,它内部包含了两个分词器,
ik_smart
和ik_max_word
, 下载地址:https://github.com/medcl/elasticsearch-analysis-ik/releases
安装的方式:解压到
$ES_HOME/plugins
目录下即可。需要注意的是,要使用一个文件夹将其包裹起来,因为ik分词器解压之后没有文件夹包裹的。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nSx5XLwL-1678946462779)(images/ik.jpg)]
ik分词的验证:
GET _analyze
{
"analyzer": "ik_smart",
"text": "回顾过往的315,让我们重新审视那些被曝光过的企业,看看消费权益的威力。"
}
GET _analyze
{
"analyzer": "ik_max_word",
"text": "回顾过往的315,让我们重新审视那些被曝光过的企业,看看消费权益的威力。"
}
pinyin就是将中文转换为拼音的方式,下载地址:https://github.com/medcl/elasticsearch-analysis-pinyin/releases?page=7
安装的方式:解压到
$ES_HOME/plugins
目录下即可。pinyin分词器是有文件夹包裹的。
GET _analyze
{
"analyzer": "pinyin",
"text": "刘德华"
}
- 因为ik、pinyin他们并没有提供的完善的拼音+汉字的前缀搜索,需要在pinyin分词器的基础上定制
- 自定义分词器
PUT users { "settings": { "analysis": { "analyzer": { // 自定义一个分词器,名字叫做 name_analyzer "name_analyzer": { // character_filter, 用的是ES官方提供的character filter // html_strip 是官方提供的一个,就是用来去掉 html标签 "char_filter": "html_strip", // tokenizer, keyword 表示不分词 "tokenizer": "keyword", // token_fitler "filter": "my_filter" } }, "filter": { "my_filter": { // type: "pinyin" 就表示我们是在pinyin分词器的基础上改 "type": "pinyin", "keep_first_letter": true, "keep_full_pinyin": false, "keep_joined_full_pinyin": true, "keep_original": true } } } } }
- 定义mapping
PUT users/_mapping
{
"properties": {
"id": {
"type": "long"
},
"name": {
"type": "completion",
// 数据写入的时候使用的分词器
"analyzer": "name_analyzer",
// 用户在前缀提示的时候,使用的分词器
"search_analyzer": "keyword"
}
}
}
- 插入数据
POST users/_doc/1 { "id": 1, "name": "刘德华" } POST users/_doc/2 { "id": 2, "name": "柳宗元" } POST users/_doc/3 { "id": 3, "name": "柳岩" } POST users/_doc/4 { "id": 4, "name": "李思思" } POST users/_doc/5 { "id": 5, "name": "李小路" } POST users/_doc/6 { "id": 6, "name": "李小小" }
插入数据之后,在倒排索引的字典中会有如下的分词结果:
刘德华 ldh liudehua 柳宗元 liuzongyuan lzy 柳岩 liuyan ly 李思思 lisisi lss 李小路 lxl lixiaolu 李小小 lxx lixiaoxiao
- 执行搜索
GET users/_search
{
"_source": false,
"suggest": {
"name_suggest": {
"prefix": "liu",
"completion": {
"field": "name",
"size": 10
}
}
}
}
“刘德华”
}
POST users/_doc/2
{
“id”: 2,
“name”: “柳宗元”
}
POST users/_doc/3
{
“id”: 3,
“name”: “柳岩”
}
POST users/_doc/4
{
“id”: 4,
“name”: “李思思”
}
POST users/_doc/5
{
“id”: 5,
“name”: “李小路”
}
POST users/_doc/6
{
“id”: 6,
“name”: “李小小”
}
> 插入数据之后,在倒排索引的字典中会有如下的分词结果:
刘德华
ldh
liudehua
柳宗元
liuzongyuan
lzy
柳岩
liuyan
ly
李思思
lisisi
lss
李小路
lxl
lixiaolu
李小小
lxx
lixiaoxiao
> 5. 执行搜索 ```js GET users/_search { "_source": false, "suggest": { "name_suggest": { "prefix": "liu", "completion": { "field": "name", "size": 10 } } } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。