正排索引:mysql为例,根据id找到一行数据
倒排索引:根据文本找多行匹配的数据,快的原因是文本(英文单词,中文语句)比mysql数据行少多了
ES | mysql |
---|---|
index(索引库) | Database(数据库) |
Type(类型) | Table(表) |
Document(文档) | Row(行) |
field(字段) | column(列) |
ES也有分片和副本机制,便于横向扩容。
Lucene可以被认为是迄今为止最先进、性能最好的、功能最全的搜索引擎库(框架)但是想要使用Lucene,必须使用Java来作为开发语言并将其直接集成到你的应用 中,并且Lucene的配置及使用非常复杂,你需要深入了解检索的相关知识来理解它 是如何工作的
Lucene缺点:
1)只能在Java项目中使用,并且要以jar包的方式直接集成项目中.
2)使用非常复杂-创建索引和搜索索引代码繁杂
3)不支持集群环境-索引数据不同步(不支持大型项目)
4)索引数据如果太多就不行,索引库和应用所在同一个服务器,共同占用硬 盘.共用空间少.
上述Lucene框架中的缺点,ES全部都能解决.
1、Solr 利用 Zookeeper 进行分布式管理,而Elasticsearch 自身带有分布式协调 管理功能。
2、Solr 支持更多格式的数据,比如JSON、XML、CSV,而 Elasticsearch 仅支持 json文件格式。
3、Solr 在传统的搜索应用中表现好于 Elasticsearch,但在处理实时搜索应用时 效率明显低于 Elasticsearch。
4、Solr 是传统搜索应用的有力解决方案,但 Elasticsearch更适用于新兴的实时 搜索应用。
ES的默认分词设置是standard,单字拆分
了ik分词器,有两种
ik_smart会将“清华大学”整个分为一个词
ik_max_word 会将“清华大学”分为“清华大学”,“清华”和“大学”
PUT /xx_index
{
"settings": {
"index": {
"analysis.analyzer.default.type": "ik_max_word"
}
}
}
GET _analyze
{
"text":"我是中国人",
"analyzer": "standard"
}
GET _analyze
{
"text":"我是中国人",
"analyzer": "ik_smart"
}
GET _analyze
{
"text":"我是中国人",
"analyzer": "ik_max_word"
}
id | name | age | sex | address |
---|---|---|---|---|
1 | 张三 | 10 | 男 | 江苏苏州 |
2 | 李四 | 20 | 男 | 苏州园区 |
3 | 王芳 | 30 | 女 | 园区华为 |
4 | 赵六 | 40 | 女 | 华为汽车 |
#-----------用户user-----------------
PUT /user
PUT /user/_doc/1
{
"name":"张三",
"age":10,
"sex":"男",
"address":"江苏苏州"
}
GET /user/_search
#批量创建文档数据
POST _bulk
{"create":{"_index":"user", "_type":"_doc", "_id":2}}
{"id":2,"name":"李四","age":"20","sex":"男","address":"苏州园区"}
{"create":{"_index":"user", "_type":"_doc", "_id":3}}
{"id":3,"name":"王芳","age":"30","sex":"女","address":"园区华为"}
{"create":{"_index":"user", "_type":"_doc", "_id":4}}
{"id":4,"name":"赵六","age":"40","sex":"女","address":"华为汽车"}
#批量获取文档数据
docs : 文档数组参数
_index : 指定index
_type : 指定type
_id : 指定id
_source : 指定要查询的字段
--------------------------------------------
GET _mget
{
"docs": [
{
"_index": "user",
"_type": "_doc",
"_id": 1
},
{
"_index": "user",
"_type": "_doc",
"_id": 2
}
]
}
GET /user/_mget
{
"docs": [
{
"_type": "_doc",
"_id": 1
},
{
"_type": "_doc",
"_id": 2
}
]
}
GET /user/_doc/_mget
{
"docs": [
{
"_id": 1
},
{
"_id": 2
}
]
}
GET /user/_mget
{
"docs": [
{
"_id": 1
},
{
"_id": 2
},
{
"_id": 3
},
{
"_id": 4
}
]
}
#批量修改文档数据,不存在则创建,存在则替换
POST _bulk
{"index":{"_index":"user", "_type":"_doc", "_id":2}}
{"id":2,"name":"李四","age":"20","sex":"男","address":"苏州园区"}
{"index":{"_index":"user", "_type":"_doc", "_id":3}}
{"id":3,"name":"王芳","age":"30","sex":"女","address":"园区华为"}
{"create":{"_index":"user", "_type":"_doc", "_id":4}}
{"id":4,"name":"赵六","age":"40","sex":"女","address":"华为汽车"}
#批量修改update
POST _bulk
{"update":{"_index":"user","_type":"_doc","_id":2}}
{"doc":{"address":"苏州园区XX"}}
{"update":{"_index":"user","_type":"_doc","_id":3}}
{"doc":{"address":"园区华为XX"}}
#批量删除
POST _bulk
{"delete":{"_index":"user", "_type":"_doc", "_id":3}}
{"delete":{"_index":"user", "_type":"_doc", "_id":4}}
DSL(Domain Specific Language 领域专用语言)
DSL查询语言中存在两种:查询DSL(query DSL)和过滤DSL(filter DSL)
说明 | query | filter |
---|---|---|
relevance | boolean yes/no | |
full text | exact values | |
not cached | cached | |
slower | faster |
无查询条件是查询所有,默认是查询所有的,或者使用match_all表示所有
GET /user/_doc/_search
{
"query": {
"match_all": {}
}
}
模糊匹配主要是针对文本类型的字段,文本类型的字段会对内容进行分词,对查询时,也会对搜索条件进行分词,然后通过倒排索引查找到匹配的数据,模糊匹配主要通过match等参数来实现
match条件还支持以下参数:
query : 指定匹配的值
operator : 匹配条件类型
minmum_should_match : 指定最小匹配的数量
# match会根据该字段的分词器
POST /user/_search
{
"from": 0,
"size": 2,
"query": {
"match": {
"address": "苏州华为"
}
}
}
term : 单个条件相等
terms : 单个字段属于某个值数组内的值
range : 字段属于某个范围内的值
exists : 某个字段的值是否存在
ids : 通过ID批量查询
#精确查询姓名 term, term查询不会对字段进行分词查询
POST /user/_search
{
"query": {
"term": {
"name": "zhangsan"
}
}
}
# match会根据该字段的分词器
POST /user/_search
{
"from": 0,
"size": 2,
"query": {
"match": {
"address": "苏州华为"
}
}
}
#多字段模糊匹配查询与精准查询 multi_match,任一字段值符合即返回
POST /user/_doc/_search
{
"query": {
"multi_match": {
"query": "张三",
"fields": [
"address",
"name"
]
}
}
}
#未指定字段条件查询 query_string , 含 AND 与 OR 条件
POST /user/_doc/_search
{
"query": {
"query_string": {
"query": "苏州 OR 华为"
}
}
}
#范围查询
#range:范围关键字
# gte 大于等于
# lte 小于等于
# gt 大于
# lt 小于
# now 当前时间
POST /user/_doc/_search
{
"query": {
"range": {
"age": {
"gte": 25,
"lte": 30
}
}
}
}
#分页、输出字段、排序综合查询
POST /user/_doc/_search
{
"query": {
"range": {
"age": {
"gte": 0,
"lte": 50
}
}
},
"from": 0,
"size": 2,
"_source": [
"name",
"age",
"address"
],
"sort": {
"age": "desc"
}
}
组合条件查询是将叶子条件查询语句进行组合而形成的一个完整的查询条件
bool : 各条件之间有and,or或not的关系
constant_score : 不计算相关度评分
must/filter/shoud/must_not 等的子条件是通过 term/terms/range/ids/exists/match 等叶子条件为参数的
注:以上参数,当只有一个搜索条件时,must等对应的是一个对象,当是多个条件时,对应的是一个数组
#Filter过滤器方式查询,它的查询不会计算相关性分值,也不会对结果进行排序, 因此效率会高一点,查询的结果可以被缓存。
POST /user/_doc/_search
{
"query": {
"bool": {
"filter": {
"term": {
"age": 30
}
}
}
}
}
GET /test_a/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"name": "java hello world"
}
}
],
"should": [
{
"match_phrase": {
"name": {
"query": "java hello world",
"slop": 50
}
}
}
]
}
}
}
“fuzziness”: 2 代表 world 可以有2个单词不一致
GET /test_a/_search
{
"query": {
"fuzzy": {
"key": {
"value": "world",
"fuzziness": 2
}
}
}
}
match:模糊匹配,需要指定字段名,但是输入会进行分词,比如"hello world"会进行拆分为hello和world,然后匹配,如果字段中包含hello或者world,或者都包含的结果都会被查询出来,也就是说match是一个部分匹配的模糊查询。查询条件相对来说比较宽松。
term: 这种查询和match在有些时候是等价的,比如我们查询单个的词hello,那么会和match查询结果一样,但是如果查询"hello world",结果就相差很大,因为这个输入不会进行分词,就是说查询的时候,是查询字段分词结果中是否有"hello world"的字样,而不是查询字段中包含"hello world"的字样。当保存数据"hello world"时,elasticsearch会对字段内容进行分词,“hello world"会被分成hello和world,不存在"hello world”,因此这里的查询结果会为空。这也是term查询和match的区别。
match_phase:会对输入做分词,但是需要结果中也包含所有的分词,而且顺序要求一样。以"hello world"为例,要求结果中必须包含hello和world,而且还要求他们是连着的,顺序也是固定的,hello that world不满足,world hello也不满足条件。
query_string:和match类似,但是match需要指定字段名,query_string是在所有字段中搜索,范围更广泛。
动态映射:
在关系数据库中,需要事先创建数据库,然后在该数据库下创建数据表,并创建表字段、类型、长度、主键等,最后才能基于表插入数据。而Elasticsearch中不需要定义Mapping映射(即关系型数据库的表、字段等),在文档写入Elasticsearch时,会根据文档字段自动识别类型,这种机制称之为动态映射。
动态映射规则如下:
静态映射:
静态映射是在Elasticsearch中也可以事先定义好映射,包含文档的各字段类型、分词器等,这种方式称之为静态映射。
index 是否创建索引 store是否存储,有些属性只做索引查询,不需要返回设置为false keyword 索引不分词存
PUT /es_db
{
"mappings": {
"properties": {
"name": {
"type": "keyword",
"index": true,
"store": true
},
"sex": {
"type": "integer",
"index": true,
"store": true
},
"age": {
"type": "integer",
"index": true,
"store": true
},
"book": {
"type": "text",
"index": true,
"store": true
},
"address": {
"type": "text",
"index": true,
"store": true
}
}
}
}
GET /es_db/_mapping
字符串:string,string类型包含 text 和 keyword。
text:该类型被用来索引长文本,在创建索引前会将这些文本进行分词,转化为词的组合,建立索引;允许es来检索这些词,text类型不能用来排序和聚合。
keyword:该类型不能分词,可以被用来检索过滤、排序和聚合,keyword类型不可用text进行分词模糊检索。
数值型:long、integer、short、byte、double、float
日期型:date
布尔型:boolean
将 book 字段设置为 keyword 映射 (只能精准查询, 不能分词查询,能聚合、排序)
将 book 字段设置为 text 映射能模糊查询, 能分词查询,不能聚合、排序)
PUT /es_db
{
"mappings": {
"properties": {
"name": {
"type": "keyword",
"index": true,
"store": true
},
"sex": {
"type": "integer",
"index": true,
"store": true
},
"age": {
"type": "integer",
"index": true,
"store": true
},
"book": {
"type": "text",
"index": true,
"store": true,
"analyzer": "ik_smart",
"search_analyzer": "ik_smart"
},
"address": {
"type": "text",
"index": true,
"store": true
}
}
}
}
1)如果要推倒现有的映射, 你得重新建立一个静态索引
2)然后把之前索引里的数据导入到新的索引里
3)删除原创建的索引
4)为新索引起个别名, 为原索引名
POST _reindex
{
"source": {
"index": "db_index"
},
"dest": {
"index": "db_index_2"
}
}
DELETE /db_index
PUT /db_index_2/_alias/db_index
老版本-7以下
PUT /db_index/_doc/1?version=1
{
"name": "Jack",
"sex": 1,
"age": 25,
"book": "Spring Boot 入门到精通",
"remark": "hello world"
}
ES新版本(7.x)不使用version进行并发版本控制 if_seq_no=版本值&if_primary_term=文档位置
_seq_no:文档版本号,作用同_version
_primary_term:文档所在位置
POST /es_sc/_update/1/?if_seq_no=1&if_primary_term=1
{
"doc": {
"name": "xxx"
}
}