全文搜索引擎目前主流的索引技术就是倒排索引的方式。传统的保存数据的方式都是:记录→单词。而倒排索引的保存数据的方式是:单词→记录, 基于分词技术构建倒排索引,每个记录保存数据时,都不会直接存入数据库。系统先会对数据进行分词,然后以倒排索引结构保存。
可以看到 Lucene 为倒排索引(Term Dictionary)部分又增加一层 Term Index 结构,用于快速定位,而这 Term Index 是缓存在内存中的,但 MySQL 的 B+tree 不在内存中,所以整体来看 ES 速度更快,但同时也更消耗资源(内存、磁盘)
创建索引 - PUT /film
查看某一个索引的分片情况 - GET /_cat/shards/film?v
删除索引 - DELETE /film
{ "id":100,
"name":"operation red sea",
"doubanScore":8.5,
"actorList":[
{"id":1,"name":"zhang yi"},
{"id":2,"name":"hai qing"},
{"id":3,"name":"zhang han yu"}
]}
{
"id":300,
"name":"incident red sea",
"doubanScore":5.0,
"actorList":[ {"id":4,"name":"zhang cuishan111"}]
}
根据主键保证幂等性
查询某一个索引中的全部文档 - GET /film/_search
根据id查询某一个文档 - GET /film/_doc/3
根据文档id,删除某一个文档 - DELETE /film/_doc/3
修改文档 - PUT /film/_doc/3 对已经存在的文档进行替换(幂等性)
{
"id":300,
"name":"incident red sea",
"doubanScore":5.0,
"actorList":[ {"id":4,"name":"zhang cuishan"}]
}
{ "doc": { "yy": "字符串" } }
Elasticsearch实际上并没有在底层执行就地更新,而是先删除旧文档,再添加新文档
POST /film/_doc/_bulk
{"index":{"_id":66}}
{"id":300,"name":"incident red sea","doubanScore":5.0,"actorList":[{"id":4,"name":"zhang cuishan"}]}
{"index":{"_id":88}}
{"id":300,"name":"incident red sea","doubanScore":5.0,"actorList":[{"id":4,"name":"zhang cuishan"}]}
POST /film/_doc/_bulk
{"update":{"_id":"66"}}
{"doc": { "name": "wudangshanshang" } }
{"delete":{"_id":"88"}}
GET /索引名/_search?q= &pretty这种方式不太适合复杂查询场景*
{ "_source": ["name", "doubanScore"]}
GET /film/_search
{
"query": {
"match": {
"actorList.name": "zhang han yu"
}
}}
GET /film/_search
{
"query": {
"match_phrase": {
"actorList.name": "zhang han yu"
}
}}
GET /film/_search
{
"query": {
"term": {
"actorList.name.keyword":"zhang han yu"
}
}}
GET /film/_search
{
"query": {
"fuzzy": {
"name": "radd"
}
}}
GET /film/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"name": "red"
}
}],
"filter": {
"term": {
"actorList.id": "3"
}
}
}}}
GET /film/_search
{
"query": {
"range": {
"doubanScore": {
"gte": 6,
"lte": 9
}}
}}
GET /film/_search
{ "query": {
"match": {
"name": "red"
}},
"sort": [ {
"doubanScore": {
"order": "asc"
}
} ]}
GET /film/_search
{"from": 0, "size": 2}
GET /film/_search
{
"query": {
"match": {
"name": "red"
}
},
"highlight": {
"fields": {"name":{} },
"pre_tags": "",
"post_tags": ""
}
}
GET /film/_search
{
"aggs": {
"groupByName": {
"terms": {
"field": "actorList.name.keyword",
"size": 10,
"order": {
"avg_score": "desc"
}
},
"aggs": {
"avg_score": {
"avg": {
"field": "doubanScore"
} }
}}
}}
.keyword 是某个字符串字段,专门储存不分词格式的副本,在某些场景中只允许只用不分词的格式,比如过滤 filter 比如聚合 aggs, 所以字段要加上.keyword 的后缀
{"analyzer": "ik_smart", "text": "我是中国人" }
{
"tokens" : [
{
"token" : "我",
"start_offset" : 0,
"end_offset" : 1,
"type" : "CN_CHAR",
"position" : 0
},
{
"token" : "是",
"start_offset" : 1,
"end_offset" : 2,
"type" : "CN_CHAR",
"position" : 1
},
{
"token" : "中国人",
"start_offset" : 2,
"end_offset" : 5,
"type" : "CN_WORD",
"position" : 2
}
]
}
<comment>IK Analyzer 扩展配置</comment>
<!--用户可以在这里配置自己的扩展字典 -->
<entry key="ext_dict">./myword.txt</entry>
<!--用户可以在这里配置自己的扩展停止词字典-->
<entry key="ext_stopwords"></entry>
PUT film01
{
"mappings": {
"movie":{
"properties": {
"id":{
"type": "long"
},
"name":{
"type": "keyword"
},
"doubanScore":{
"type": "double"
},
"actorList":{
"properties": {
"id":{
"type":"long"
},
"name":{
"type":"keyword"
}
} } }
} }}
POST _reindex
{ "source": {
"index": "my_index_name"
},
"dest": {
"index": "my_index_name_new"
}}
应用场景 - 给多个索引分组,把多个索引归并到一组
给索引的一个子集创建视图相当于给 Index 加了一些过滤条件,缩小查询范围
创建索引 并指定别名
PUT flim01
{ "aliases": {
"film_chn_3_aliase": {}
},
GET /_cat/aliases
POST /_aliases
{ "actions": [
{ "remove": { "index": "movie_chn_1", "alias": "movie_chn_query" }},
{ "remove": { "index": "movie_chn_2", "alias": "movie_chn_query" }},
{ "add": { "index": "movie_chn_3", "alias": "movie_chn_query" }}
]
}
应用场景
分割索引
分割索引就是根据时间间隔把一个业务索引切分成多个索引。比如 把 order_info 变成 order_info_20200101,order_info_20200102 这样做的好处有两个:
结构变化的灵活性
因为 ES 不允许对数据结构进行修改。但是实际使用中索引的结构和配置难免变化,那么只要对下一个间隔的索引进行修改,原来的索引维持原状。这样就有了一定的灵活性。要想实现这个效果,我们只需要在需要变化的索引那天将模板重新建立即可。
查询范围优化
因为一般情况并不会查询全部时间周期的数据,那么通过切分索引,物理上减少了扫描数据的范围,也是对性能的优化。
创建模板
PUT _template/template_film
{"index_patterns": ["film_test*"],
"settings": {
"number_of_shards": 1
},
"aliases" : {
"{index}-query": {},
"film_test-query":{}
},
"mappings": {
"_doc": {
"properties": {
"id": {
"type": "keyword"
},
"movie_name": {
"type": "text",
"analyzer": "ik_smart"
}}
}}}
GET _cat/templates
GET _template/template_film*