Elasticsearch
一. 倒排索引和正排索引
正向索引在数据库领域用的比较多,它是将全文进行分词,用户查询的时候就到所有的分词中去匹配,如果有匹配到分词,最终该文档就出现结果集中。
倒排索引在搜索引擎领域用的比较多,它也会先进行分词,接着将分词与文档进行映射,分词就构成了一个词典,当用户查询的时候,首先到词典中查找对应的分词,然后将对应的文档获取到。
二. ELK
Elasticsearch是真个elastic核心产品, 我们搜索都是该软件来实现的。
Logstash是一个数据输入、过滤、输出的管道,负责将不同来源数据过滤处理之后导入到Elasticsearch.
Kibana是一个操作 Elasticsearch的可视化界面,包括一些数据的统计模型。
三. Logstash的数导入
一, 将提供的数据集中
movies.csv
拷贝到 logstash的家目录下。
二,将配置文件拷贝到 LOGSTASH_HOME/config 目录下。
三, 依据情况修改 logstash.conf 配置文件中的路径。
三,导入数据,首先进到 LOGSTASH_HOME/bin, 打开dos命令行,执行如下的命令
# 具体执行的时候,将 LOGSTASH_HOME 缓存具体的Logstash的家目录logstash -f LOGSTASH_HOME/config/logstash.conf
四. 名词
索引,类似于RDBMS中数据库的概念,在ES中有三层含义:1. 文档的集合;2. 倒排索引;3.XXX
type,类似于数据库中表的概念,在ES7以下的版本中,是有type来区分不同的数据集;但是ES7之后,统一都叫做
_doc
文档,类似于数据库中记录的概念,数据的格式是一个JSON.
属性,就是文档中的字段的名字。
五. 基本的查询
查看所有的索引:
GET _cat/indices
查看电影数据集的内容:
GET movies/_search
查看电影数据集的数量:
GET movies/_count
查看指定id的文档:
GET movies/_doc/1
六. 基本的增删查改
添加,自动生成id
POST user/_doc{"firstname": "Jack","lastname": "Ma"}
添加,指定id
POST user/_doc/2{"firstname": "Pony","lastname": "Ma"}
删除
DELETE uesr/_doc/2
修改
POST user/_update/2{"doc": {age:34}}
批量添加
POST users/_bulk{"index": {}}{"firstname": "Rod", "lastname": "Jhonson"}{"index": {"_id": 2}}{"firstname": "Douge", "lastname": "Lee"}
七. Request Body查询
Request Body的查询需要的记住的就四个:
matchmulti_matchrangeboolmatch_phrase (用的比较少)
查询电影中名字包含的所有电影
GET movies/_search{"query": {"match": {"title": ""}}}
查询电影的在1992年到1993年上映的所有的电影
GET movies/_search{"query": {"range": {"year": {"gte": 1992,"lte": 1993}}}}
查询电影中包含有的所有的电影
GET movies/_search{"query": {"multi_match": {"fields": ["title", "year"],"query": }}}
查询电影的名字中包含有 beautiful 或者 mind 的电影
GET movies/_search{"query": {"match": {"title": "beautiful mind"}}}
查询电影的名字中包含有beautiful和mind所有的电影
GET movies/_search{"query": {"match": {"title": {"query": "beautiful mind","operator": "and" // or}}}}
查询电影的名字中包含有 “beautiful mind” 短语的电影
GET movies/_search{"query": {"match_phrase": {"title": "beautiful mind"}}}
查询电影的名字中包含有 mind 或者 beautiful 的所有的电影,按照上映的年份进行倒序排序
GET movies/_search{"query": {"match": {"title": "beautiful mind"}},"sort": [{"year": {"order": "desc"}}]}
查询所有的战争片,然后分页
GET movies/_search{"query": {"match": {"genre": "war"}},"from": 0,"size": 10}
查询所有的战争片,并且是在上映的,然后分页
GET movies/_search{"query": {"bool": {"must": [{"match": {"genre": "war"}},{mathc: {"year": }}]}},"from": 0,"size": 10}
八. 分词器
ES内置了很多的分词,例如: stop、standard, simple, whitespace… 但是他们只针对英文处理。
ES的分词处理是 analysis, 它是通过 analyzer 来实现,analyzer 对于分词的处理分为三个步骤:
character filter 过滤html标签tokenizer 切词,将一句话或者一个词切成一个个小的子或者词token filter, 将token处理之后的结果进一步处理,例如,去停用词、转大小写、转拼音。
8.1 IK和pinyin分词的安装
IK是中文分词社区中用的最多的一个分词器。
IK分词器的安装:在 ES_HOME/plugins 目录下创名为
ik
的目录,然后将 zip 文件拷贝到目录下,然后即可。
IK分词器的安装:在 ES_HOME/plugins 目录下创名为
pinyin
的目录,然后将 zip 文件拷贝到目录下,然后即可。
8.1.1 配置词库
因为IK分词器团队不可能将很多我们业务词汇加入到官方词库中,所以会导致有些词被切割了,所以我们需要配置自己的词库。
第一步,在IK分词的解压目录的 config 目录下创建一个名为
custome
的文件夹
第二步,在文件夹下创建名为
my.dic
, 将自己的业务词库加进去(一个词一行),保存格式为 UTF-8
第三步,配置自定义的词典,打开 config 目录下的
IKAnalyzer.cfg.xml
,将自定义的词典配置进去,如下所示:
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE properties SYSTEM "/dtd/properties.dtd"><properties><comment>IK Analyzer 扩展配置</comment><!--用户可以在这里配置自己的扩展字典 --><entry key="ext_dict">customer/my.dic</entry><!--用户可以在这里配置自己的扩展停止词字典--><entry key="ext_stopwords"></entry><!--用户可以在这里配置远程扩展字典 --><!-- <entry key="remote_ext_dict">words_location</entry> --><!--用户可以在这里配置远程扩展停止词字典--><!-- <entry key="remote_ext_stopwords">words_location</entry> --></properties>
九. 案例
实现类似于电商和百度的搜索功能。
9.1 配置自定义分词器
PUT stars{"settings": {"analysis": {"analyzer": {// 表示我们自定义的analyzer, 名字叫做 my_star_analyzer"my_star_analyzer": {// char_filter: "html_strip", 去除文本中html标签, html_strip是ES内置的一个 character filter"char_filter": "html_strip",// keyword 也是 ES内置的一个 tokenizer, 表示对我们的原文不动"tokenizer": "keyword",// filter就是 token filter, 需要自定义了"filter": "star_name_filter"}},// 自定义filter"filter": {// 自定义的filter的名字"star_name_filter": {"type":"pinyin","keep_separate_first_letter" : false,"keep_full_pinyin" : false,"keep_original" : true,"lowercase" : true,"keep_joined_full_pinyin": true,"remove_duplicated_term" : true}}}}}
9.2 测试
针对如上的自定义分词器进行测试, 测试是否通过(满足我们的业务需求)
GET stars/_analyze{"analyzer": "my_star_analyzer","text": ["刘德华"]}
9.3 插入样本数据
插入样本数据的目的就是为了获取mapping
POST stars/_doc{"name": "刘德华"}
9.4 获取mapping信息
获取mapping信息
GET starts
拷贝其mapping信息
9.5 定义mapping
将
9.4
节获取到的mapping, 结合9.1
节自定义的分词器,创建业务所需的mapping
PUT stars/_mapping{"properties" : {"name" : {// 前缀的类型是 completion"type" : "completion",// 数据写到ES的时候,所采用的分词,是我们在上面自定义的"analyzer": "my_star_analyzer",// 表示用户在搜索的时候,不分词,就用户传入什么内容,就原封不动的丢到ES进行匹配"search_analyzer": "keyword"}}}
9.6 写入数据
POST stars/_bulk{"index": {"_id": 1}}{"name": "李小璐"}{"index": {"_id": 2}}{"name": "柳岩"}{"index": {"_id": 3}}{"name": "刘德华"}{"index": {"_id": 4}}{"name": "蔡徐坤"}
9.7 测试
样本一:
// 建议搜索GET stars/_search{"_source": "", "suggest": {// 自己取的建议的名字"start_name_prefix_suggest": {"prefix": "ldh,"completion": {"field": "name"}}}}
样本二:
// 建议搜索GET stars/_search{"_source": "", "suggest": {// 自己取的建议的名字"start_name_prefix_suggest": {"prefix": "lixiao,"completion": {"field": "name"}}}}
十一. 面试问题
数据写入到ES的过程?
character_filtertokenizertoken filter
工作中你用在哪里?怎嘛用的?
搜索提示,类似京东、百度的搜索提示。内容检索。
搜索提示怎么做?
先根据IK分词、和 pinyin 分词自定义自己的分词器,配置 character_filter , tokenizer,token filter这些信息。设置mapping信息,将我们用于提示的属性的类型设置completion
, 以及分词器设置成我们自定义的分词器。导入数据(Logstash), 程序导入。代码实现,前端展示。
内容检索怎么做?
定义mapping信息,将其分词器设置成 ik_smart 分词器。写入数据。根据用户搜索提示的信息,选中对应的词条,然后使用match
和multi_match
进行匹配。检索数据使用高亮展示。
你的数据是怎么同步?增量数据?