ES基础
如何实现商品的搜索
-
使用SQL语句的like查询
-
select * from product where name like "%手机%"
-
当数据量超过千万的时候,效率严重低下
-
-
使用全文检索
- 主流搜索技术
什么是全文检索
-
数据的分类
- 结构化数据
- 固定格式、固定长度、数据类型固定(mysql数据库)
- 非结构化数据
- 格式不固定、长度不固定、数据类型不固定(磁盘文件)
- 结构化数据
-
结构化数据搜索
- SQL语句
-
非结构化数据的搜索
-
需求:找出文件中包含hello的文件
-
1、顺序扫描:数据量非常庞大时性能很差
-
2、把非结构化数据变成结构化数据
- 基于结构化数据创建索引,然后再查询
- 索引:是一个独立的数据结构,b+树。为了提高效率需要独占磁盘空间
- 停用词:没有意义的词,比如and、a、an、the
- 全文检索:先对内容进行分词处理(按空格拆分、去除标点、转换大小写、合并相同词、去除停用词,最终获得单词列表,记录单词与文件的对应关系)
- 先创建索引,然后查询索引的过程中就叫全文检索
-
-
全文检索的应用场景
- 搜索引擎
- 百度、谷歌...
- 站内搜索
- 商品搜索、论坛搜索、微博搜索
- 磁盘搜索
- 查找磁盘上的文件
- 只要有搜索的地方都可以使用全文检索
如何实现全文检索
- 使用luccene,java中唯一的全文检索技术
- 是一个全文检索工具包
- Solr、ElasticSearch
- 都是基于luccened的全文检索技术。独立运行、支持集群
- 实时搜索ES的性能更好
全文检索的流程
- 创建索引
- 采集数据
- 可以各种新式的数据源
- 搜索引擎:爬虫
- 站内搜索:数据库
- 磁盘搜索:磁盘上的文件
- 创建文档对象
- 把原始文档进行封装。Document对象,包含多个Field,不同的document有不同的field
- 分析文档
- 对需要分析的field进行分析处理(按空格拆分、去除标点、转换大小写、合并相同词、去除停用词,最终获得单词列表,记录单词与文件的对应关系)
- 创建索引
- 索引(单词列表)
- 文档对象(Document文档)
- 索引与文档的对应关系(倒排序链表)
- 采集数据
- 查询索引
- 用户接口
- 用户输入查询内容
- 输入可以是一个关键词或者一句话
- 封装查询条件
- 把用户输入的内容进行分词处理。得到一个单词列表
- 需要指定查询的field
- 查询条件:field:value
- 执行查询
- 在索引中根据查询的条件查询对应的字段,找到对应的关键词
- 如果关键词在索引中存在就能查询到结果,如果不存在就没有结果
- 根据关键词找到对应的文档ID列表,根据文档ID查询到对应的Document对象
- 展示结果
- 关键词的高亮显示、分页处理,根据相关度进行排序
- 用户接口
相关度排序
- SEO:搜索引擎优化
- 两个指标:
- TF:关键词在文章中出现的频率。TF越大相关度越高。
- DF:所有文档中关键词出现的频率。DF越大相关度越低。例如 and
- 根据TF和DF计算出一个相关度的得分,得分越高相关度越高,文档根据相关度得分进行降序排列
ES的多应用场景
- 搜索引擎
- 存储和分析海量数据(ELK对日志进行存储和分析)
ES下载
- 官网下载
- 自己下载后保存到自己的百度云等等...
ES安装
- docker上安装
- ElasticSearch
- ElasticSearch-head客户端:使用nodejs开发的
- 安装kibana
- windows
- Linux
- Apple
ES索引的创建
-
基础概念
- mysql -> 数据库 -> 表 -> 行 -> 列
- es -> 索引库 ->(type) -> Document -> field
-
ES API的使用风格
- restful
- 使用不同形式的http方法对资源进行操作。
- 增:put(post)
- 删:delete
- 改:post(put)
- 查:get
-
索引的管理
- 创建索引库
- 方法:put
- url:http://ip:9200/{索引名称}
- 分片:早期默认5片、ES7默认1片
- 副本:1片,每个分片默认1个副本
- 删除索引库
- 方法:delete
- url:http://ip:9200/{索引名称}
- 创建索引的同时设置mapping和Setting
-
文档格式的定义
-
文档中包含
- 字段的名称
- 数据类型(type)
- 是否索引(index)
- 是否存储(store)
- 是否分词(analyzer)
-
方法:put
-
请求体如下
{ "mappings": { "properties":{ "id":{ "type":"long" }, "title":{ "type":"text", "analyzer":"ik_smart", "index":true, "store": "true" }, "mobile":{ "type":"keyword", "store": "true", "index":true }, "comment":{ "type":"text", "analyzer":"ik_smart", "store": "true", "index":true } } }, "settings": { "number_of_shards": 5, "number_of_replicas": 1 } }
-
- 创建索引的后设置mapping
-
方法:put、post
-
请求体如下
{ "properties":{ "id":{ "type":"long" }, "title":{ "type":"text", "analyzer":"standard", "store": "true", "index":true }, "mobile":{ "type":"keyword", "store": "true", "index":true }, "comment":{ "type":"text", "analyzer":"standard", "store": "true", "index":true } } }
-
- 创建索引库
ES文档的管理(增、删、改)
-
添加文档
-
方法:put
-
url:http://ip:9200/{索引名称}/_doc/{id} 其中id与字段id应该设置一样的值
{ "id":3, "title":"题目23", "mobile":"18963607583", "comment":"这种方式把查询参数构建成JSON格式的数据" }
-
-
删除文档
- 方法:DELETE
- url:http://ip:9200/{索引名称}/_doc/{id} 其中id与字段id应该设置一样的值
-
修改文档
-
方法:post
-
url:http://ip:9200/{索引名称}/_doc/{id} 其中id与字段id应该设置一样的值
{ "id":3, "title":"题目23修改", "mobile":"18963607583修改", "comment":"这种方式把查询参数构建成JSON格式的数据修改" }
-
-
批处理(增、删、改)
-
方法:post、put
-
请求体
{action:{metadata}} {请求体数据信息json格式} //请求数据必须写在一行中 {action:{metadata}} {请求体数据信息json格式} {action:{metadata}} {请求体数据信息json格式} {action:{metadata}} {"doc":{请求体数据信息json格式}} -
action对应取值
- create:创建一个文档,如果文档不存在就创建
- index:创建一个新的文档,如果文档存在就更新
- update:批量更新文档
- delete:批量删除,不需要有请求体
-
metadata对应取值
- _index:要写入的索引信息
- _type:要写入的type
- _id:要写入文档的id
-
案例
{"index":{"_id":1}} {"id":1, "title":"这是一篇文章", "content":"xxxxx", "comment":"备注信息", "mobile":"13344556677"} {"index":{"_id":2}} {"id":2, "title":"这是一篇文章", "content":"xxxxx", "comment":"备注信息", "mobile":"13344556677"} {"index":{"_id":3}} {"id":3, "title":"这是一篇文章", "content":"xxxxx", "comment":"备注信息", "mobile":"13344556677"}
-
ES文档的查询
-
根据id查询指定Document
- 方法:GET
- URL:http://ip:9200/{索引名称}/_doc/{id}
-
查询的语法
-
方法:POST
-
URL:
-
请求体
{ "query":{ "xxxx" } }-
查询全部数据match_all
{ "query":{ "match_all":{} } } -
精确匹配term
{ "query":{ "term":{ "comment":"苹果" } } } -
模糊匹配1、match
{ "query": { "match": { "title": "题目hahha" } } } -
模糊匹配2、query_string
{ "query": { "query_string": { "default_field": "title", "query": "题目hahha" } } } -
多字段模糊匹配 multi_match
{ "query": { "multi_match": { "query": "浏览器", "fields": ["title","comment"] } } } -
组合条件查询
-
逻辑关系:
-
must:必须满足,相当于是AND
-
should:应该满足,相当于OR
-
must_not:必须不能满足,相当于NOT
-
filter:过滤
- filter查询是不进行打分处理。查询性能好于query
- filter节点中可以包含多个查询条件,条件之间层层过滤
-
{ "query":{ "bool":{ "must":[], "should":[], "must_not":[], "filter":[] } } } { "query":{ "bool":{ "must":[ { "match":{ "title":"apple" } }, { "match":{ "content":"apple" } } ], "filter":[ { "term":{ "title":"apple" } } ] } } } -
-
高亮处理
-
在查询结果中将查询的关键词左右两边分别加上成对的html标签
-
高亮的处理在查询条件中指定
{ "query":{ "bool":{ "must":[ { "term":{ "title":"apple" } } ] } }, "heightligth":{ "fields":{ "title":{}, "content":{} } "pre_tag":"<em>", "post_tag":"</em>" } }
-
-
查询结果分页
{ "query":{ "multi_match":{ "query":"abcdefg", "fields":["title","content"] } }, "highlight": { "fields": { "title": {}, "content": {} }, "pre_tags": "<em>", "post_tags": "</em>" }, "from": 10, "size": 5 }
-
-
中文分词器
- 国产:Ik-analyzer
- ik_smart:快速分词,速度快,粒度比较粗
- ik_max_word:最大数量分词,速度慢,粒度细
- Ik的使用方法
- 下载ES对应版本的ik分词器
- 把分词器解压缩
- 把解压之后的目录放到{ES}/plugin目录下
- 重启ES
- 索引一旦创建完毕不能修改分词器
- field的数据类型
- 数值类型:int、long、folat、double
- 字符串
- text:需要分词的字段必须使用text,只有text类型才能支持分词器
- keyword:不需要对字段的内容进行分词处理(身份证号、手机号、订单号等)
- 日期:data
- 字段的三个属性
- 是否分词(analyzer):是否是text类型
- 是否索引(index)
- 是否对field的内容进行索引
- 不分词也可以把field的内容添加到索引中
- 是否存储(store)
- 无论是否存储,不影响分词、创建索引、搜索
- 影响的是能否在查询结果中看到原始内容