搜索引擎
https://blog.csdn.net/icanlove/article/details/125636857
ElasticSearch
官网:https://www.elastic.co/guide/cn/index.html
Elasticsearch 是一个实时的分布式存储搜索分析的引擎。Elasticsearch是面向文档,一切都是Json。
端口:
9200端口为浏览器访问http协议的RESTful端口。
9300端口为es集群内部组件通信端口。
1)Elasticsearch与关系型数据库对比
关系型数据库也能做到实时的存储搜索分析,相对于数据库,Elasticsearch的强大之处就是可以模糊查询,虽然数据库也有like来支撑模糊查询,但是数据库这类的查询是不走索引的。
关系型数据库 | Elasticsearch |
---|---|
数据库 Database | 索引 Index |
表 Table | 类型 Type(7.x版本已被移除) |
行 Row | 文档 Docment |
列/字段 Columns | 列/字段 Field |
Schema | Mapping |
SQL | DSL |
2)应用场景
使用场景 | 详情 |
---|---|
搜索 | 模糊查询 |
日志数据分析 | logstash采集日志,elasticsearch进行复杂的数据分析。ELK技术(elasticsearch+logstash+kibana) |
3)可视化工具:Kibana
# sql查询plugin
{{ES地址}}/_plugin/kibana/app/opendistro-query-workbench
# 控制台
{{ES地址}}_plugin/kibana/app/dev_tools#/console?_g=
# 例如
https://vpc-social-test-ozcc7xn7dcd6el6yfgsfwjqdze.cn-north-1.es.amazonaws.com.cn/_plugin/kibana/app/dev_tools#/console?_g=
数据结构
字段类型不一样,存储不一样。
默认:倒排索引默认所有字段都启用,正排索引 Doc Values 非 text 类型默认启用, source (存储原始文档的 所有字段的 json 结构数据)和 store (存储指定字段的 json 数据) 的启用与否需要结合业务实际。假设:正排索引、倒排索引、_source 、store 都启用了,存储肯定会增加,但不是线性的 4倍。
https://blog.csdn.net/lijingjingchn/article/details/113256660
Inverted Index 倒排/反向索引
倒排索引列出了出现在任何文档中的每个唯一单词,并标识了每个单词出现的所有文档。
索引可以认为是文档的优化集合,每个文档都是字段的集合,这些字段是包含数据的键值对。
默认情况下,Elasticsearch 对每个字段中的所有数据建立索引,并且每个索引字段都具有专用的优化数据结构。
例如,文本字段存储在倒排索引中,数字字段和地理字段存储在BKD树中。
数据类型 | 数据结构 |
---|---|
text/keyword | 倒排索引 |
数字/地理位置 | BKD树 |
不同字段具有属于自己字段类型的特定优化数据结构,并具备快速响应返回搜索结果的能力使得 Elasticsearch 搜索飞快!
Doc Values 正排索引
fielddata text的正排索引
_source 不构建索引但存储
source字段会导致索引内的存储开销。可以将其禁用。
禁用 _source 后,如下操作将不可用:update, update_by_query 和 reindex API 高亮操作,所以,要在存储空间、业务场景之间权衡利弊后选型。
store 构建索引但不存储
_cluster集群
分片设置
PUT /_cluster/settings
{
"transient": {
"cluster": {
"max_shards_per_node":2000
}
}
}
索引index
## 查询当前所有的index
GET _cat/indices
## 查看索引的信息
GET xxx_index_name
## 响应
{
"xxx_index_name" : {
"aliases" : { },
"mappings" : {
"properties" : {
"字段" : {
"type" : "字段类型"
}
}
},
"settings" : {
"index" : {
"creation_date" : "1640687761530",
"number_of_shards" : "1",
"number_of_replicas" : "0",
"max_result_window" : "100000",
"uuid" : "1wZItKObSIKIey1zaNZesg",
"version" : {
"created" : "7100299"
},
"provided_name" : "t_acats_transfer"
}
}
}
}
## 查看索引的mapping
GET xxx_index_name/_mapping
## 查看索引的设置
GET xxx_index_name/_settings
## 查看索引的别名
GET xxx_index_name/_alias
_mapping 映射
映射是定义文档的过程,文档包含哪些字段,这些字段是否保存,是否索引,是否分词等
#创建索引映射
PUT xxx_index_name
{
"mappings":{
"properties": { # properties定义其属性
"field_name": { # 字段名
"type": "类型", # type:字段类型
"index": true, # index:是否索引,默认为true
"store": false, # store:是否存储,默认为false
"analyzer": "" # analyzer:分词器
}
}
}
}
#注
# 1)mapping生成后是不允许修改和删除的字段的。所以需要提前合理的的定义mapping。
# 2)给已有索引增加字段
PUT xxx_index_name/_mapping
{
"properties": { # properties定义其属性
"field_name": { # 字段名
"type": "类型", # type:字段类型
"index": true, # index:是否索引,默认为true
"store": false, # store:是否存储,默认为false
"analyzer": "" # analyzer:分词器
}
}
}
type字段类型
字符串类型text , keyword
text | keyword | |
---|---|---|
会分词,然后进行索引 | 不进行分词,直接索引 | |
支持模糊、精确查询 | 支持模糊、精确查询 | |
不支持聚合 | 支持聚合 |
text
支持分词,用于全文搜索。如果安装了IK分词插件,可以指定IK分词器。
# 字段需要模糊搜索,又需要精确匹配
"xxx_field_name": {
"type": "text",
"analyzer": "ik_smart",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
# 字段只需要模糊搜索
"xxx_field_name": {
"type": "text",
"analyzer": "ik_smart",
}
keyword
不支持分词,用于聚合和排序。
# 字段需要精确匹配
"xxx_field_name": {
"type": "keyword"
}
日期类型date
"xxx_field_name": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss"
}
数字类型long,integer,short,byte,double,float,half_float,scaled_float
布尔类型boolean
二进制类型binary
范围类型integer_range,float_range,long_range,double_range,date_range
_settings 索引设置
# 要显示的字段
{
"mappings" : {
"_source" : {
"excludes" : []
}
}
}
# 字段会被索引,则可以用来进行搜索。默认值就是true
"xxx_field_name": {
"index": false
}
# 字段不会被索引,不能用来搜索
"xxx_field_name": {
"index": false
}
有的时候,我们可能不需要所有的字段都返回,那我们可以用source来指定需要返回的具体字段。
elasticsearch中max_result_window默认10000限制修改
注意:
-
from + size的大小不能超过index.max_result_window这个参数的设置,默认为10000
-
需要搜索分页,可以通过from size组合来进行。from表示从第几行开始,size表示查询多少条文档。from默认为0,size默认为10
3.将索引库默认值设置为了最大允许值,Elasticsearch支持的最大值是2^31-1,也就是2147483647
-
此方法是设置所有索引,如果需要更改索引需要将_all改成具体索引
-
即使换成_all,对于新增的索引,还是默认的10000
# 设置ES单页限制
PUT xxx_index_name/_settings
{
"index":{
"max_result_window":10000000
}
}
curl -H "Content-Type: application/json" -XPUT 'http://[ES地址]:80/xxx_index_name/_settings' -d '{"index":{"max_result_window":[单页大小,默认10000]}}'
_source
默认情况下,Elasticsearch里面有2份内容,一份是原始文档,也就是_source字段里的内容,我们在Elasticsearch中搜索文档,查看的文档内容就是_source中的内容。另一份是倒排索引,倒排索引中的数据结构是倒排记录表,记录了词项和文档之间的对应关系。
includes需要返回的字段
"mappings" : {
"_source" : {
"excludes" : [ "bizContent", "beforeModify", "afterModify" ]
},
"properties" : {
}
}
excludes返回排除的字段
"mappings" : {
"_source" : {
"excludes" : [ "bizContent", "beforeModify", "afterModify" ]
},
"properties" : {
}
}
_alias 索引别名
POST /_aliases
{
"actions": [
{ "add": { "index": "xxx_index_name", "alias": "xxx_index_name_别名" }}
]
}
POST /_aliases
{
"actions": [
{ "remove": { "index": "xxx_index_name", "alias": "xxx_index_name_别名" }}
]
}
CRUD
新增
#插入单条数据,用PUT或POST都可以
PUT xxx_index_name/xxx/id
{"key1":"value1","key2":value2}
_bulk 多条
#插入数据-多条-指定主键ID
PUT xxx_index_name/_bulk
{ "index":{"_id":xxx-id1}} ## index表示新插入数据。插入数据时如果指定的_id已经存在,那么新插入的数据会直接替换原ID的数据
{"key1":"value1","key2":value2}
{ "index":{"_id":xxx-id2}} ## index表示新插入数据。插入数据时如果指定的_id已经存在,那么新插入的数据会直接替换原ID的数据
{"key1":"value3","key2":value4}
#插入数据-多条-不指定主键ID
PUT xxx_index_name/_bulk
{ "index":{}} ## index表示新插入数据
{"key1":"value1","key2":value2}
{ "index":{}} ## index表示新插入数据
{"key1":"value3","key2":value4}
删除
#删除索引
DELETE xxx_index_name
#根据ID进行删除数据
DELETE xxx_index_name/xxx-id
#根据查询结果删除数据
POST xxx_index_name/_delete_by_query
{
#DSL语句
"query": {}
}
POST trade_op_log/_delete_by_query
{
"query": {
"match": {
"subBizType": "ORDER_CONFIG_TRADING_STATUS"
}
}
}
curl -XDELETE https://xxx/xxx_index_name
修改
#根据ID进行修改数据
POST xxx_index_name/id-n1/_update
{
"script": {
"source": "ctx._source.key1=params.key1",
"lang": "painless",
"params": {
"key1": "new-value1"
}
}
}
#根据查询结果修改数据
POST xxx_index_name/_update_by_query
{
"script": {
"source": "ctx._source.key1=params.key1",
"lang": "painless",
"params": {
"key1": "new-value1"
}
}
}
POST xxx_index_name/_update_by_query
{
"script": {
"source": "ctx._source.limitPrice=params.limitPrice",
"lang": "painless",
"params": {
"limitPrice": "1815.50"
}
},
"query": {
"match": {
"_id":"031SM2TBNM6DT0KHJK3G000000"
}
}
}
POST xxx_index_name/_update_by_query
{
"script": {
"source": "ctx._source.parentAccountId=params.parentAccountId",
"lang": "painless",
"params": {
"parentAccountId": "848265993636827136"
}
},
"query": {
"match": {
"accountId":"848325498923929600"
}
}
}
POST bo_st_order_20230729_01/_update_by_query
{
"script": {
"source": "ctx._source.closeContracts=params.closeContracts",
"lang": "painless",
"params": {
"closeContracts": "5TJ6HQQ6GGGJA39M8GSMJ6B:1,5TJ6HQQ6GGGJA39M8GSM76B:1"
}
},
"query": {
"match": {
"id":"03237565O66DT0KHJP9S000000"
}
}
}
查询 _search
Elasticsearch 默认会分页返回10条数据,不会返回所有数据。
# 查询结果
{
"took" : 1, # 查询花费时间,单位是毫秒
"timed_out" : false, # 是否超时
"_shards" : { # 分片信息
"total" : 3,
"successful" : 3,
"skipped" : 0,
"failed" : 0
},
# 搜索结果对象
"hits" : {
"total" : { # 搜索到的总条数
"value" : 5275,
"relation" : "eq" # eq;gte
},
"max_score" : 1.0, # 所有结果中文档得分的最高分
"hits" : [ # 搜索结果的文档对象数组,每个元素是一条搜索到的文档信息
{
"_index" : "t_account_master", # 索引库
"_type" : "_doc", # 文档类型
"_id" : "00GCALMMJQLM1DTM00O09V4NOB", # 文档id
"_score" : 1.0, # 文档得分
"_source" : {
"字段1" : "值1",
"字段2" : "值2",
...
"字段n" : "值n"
} # 文档的源数据
}
]
}
}
参考:https://www.elastic.co/guide/en/elasticsearch/reference/current/search.html
query 查询条件(DSL)
Elasticsearch提供了一个可以执行查询的JSONE风格的DSL。这个被称为Query DSL,该查询语言非常全面。
Elasticsearch有Query和Filter两种不同的Context。
Query Context,会进行相关性算分
Filter Context,不会进行相关性算分,这种方式可利用缓存来提高检索的速度和性能。
GET /_search
{
"query": {
"bool": {
"must": [
{ "match": { "title": "Search" }},
{ "match": { "content": "Elasticsearch" }}
],
"filter": [
{ "term": { "status": "published" }},
{ "range": { "publish_date": { "gte": "2015-01-01" }}}
]
}
}
}
DSL | |
---|---|
script | |
source | |
lang | lang=painless表示使用painless脚本语言来编写script来完成。 |
params | |
lang | =painless,表示使用painless脚本语言来编写script来完成 |
ctx | ctx为当前事务,ctx._source表示当前定位的document,params表示本次更新用到的数据,source则表示更新操作,通俗来讲就是用params的数据+source的操作一起完成更新。 |
_source指定返回字段
表示只显示哪一些字段,就像数据库的select xxx
GET xxx_index_name/_search
{
"_source": ["address","name"],
"query": {
"match_all": {}
}
}
includes需要返回的字段
GET xxx_index_name/_search
{
"_source" : {
"excludes" : [ "address", "name" ]
},
"query": {
"match_all": {}
}
}
excludes返回排除的字段
GET xxx_index_name/_search
{
"_source" : {
"excludes" : [ "beforeModify", "afterModify" ]
},
"query": {
"match_all": {}
}
}
match_all 查询所有
GET xxx_index_name/_search
{
"query": {
"match_all": {}
}
}
match 全文检索
match即全文检索,对检索字段进行分词匹配,会按照响应的评分 _score 排序,原理是倒排索引。
and
match会把查询条件进行分词,然后进行查询。多个词条之间是or的关系
GET xxx_index_name/_search
{
"query": {
"match": [
{
"address": "湖南长沙"
}
]
}
}
# 查询结果:不仅会查询到长沙,而且与湖南相关的都会查询到。
or
GET xxx_index_name/_search
{
"query": {
"match": {
"address": {
"query": "湖南长沙",
"operator": "and"
}
}
}
}
# 查询结果:同时包含湖南跟长沙的才会查询到,例如湖南长沙岳麓区。
match_phrase 精确匹配
GET xxx_index_name/_search
{
"query": {
"match_phrase": {
"address.keyword": "湖南长沙"
}
}
}
# 查询结果:一)分词后所有词项都要出现在指定字段中,二)字段中的词项顺序要一致
multi_match 多字段匹配
GET xxx_index_name/_search
{
"query": {
"multi_match": {
"query": "长沙",
"fields": [
"city",
"address"
]
}
}
}
# 查询结果:在city字段和address字段中查询湖南长沙。
term 精确值匹配
文档中必须包含整个搜索词汇,比如 搜索"汽车保养",那么文档中 也必须包含 “汽车保养” 这一复合词,一般在创建索引时会指定 type 为 keywords,这样子整个就可以在倒排索引中了;
GET xxx_index_name/_search
{
"query":{
"term":{
"xxx":vvv
}
}
}
terms 多值精准匹配
GET xxx_index_name/_search
{
"query":{
"term":{
"xxx":[v1,v2,v3]
}
}
}
range 范围查询
GET xxx_index_name/_search
{
"query":{
"range": {
"xxx": {
"gte": 1000.0,
"lt": 2800.00
}
}
}
}
操作符 | 说明 |
---|---|
gt | 大于 |
gte | 大于等于 |
lt | 小于 |
lte | 小于等于 |
fuzzy 模糊查询
它允许用户搜索词条与实际词条的拼写出现偏差,但是偏差的编辑距离不得超过2
GET xxx_index_name/_search
{
"query":{
"fuzzy":{
"xxx":"vvv"
}
}
}
bool 联合
子句 | 类型 | 影响结果 |
---|---|---|
must | Query Context | 必须匹配。贡献算分 |
shoud | Query Context | 选择性匹配,至少满足一条。贡献算分 |
must_not | Filter Context | 过滤子句,必须不能匹配,但不贡献算分 |
filter | Filter Context | 过滤子句,必须匹配,但不贡献算分 |
Bool查询语法有以下特点
- 子查询可以任意顺序出现
- 可以嵌套多个查询,包括bool查询
- 如果bool查询中没有must条件,should中必须至少满足一条才会返回结果。
must 必须匹配AND
必须达到must所列举的所有条件。AND
{
"query":{
"bool":{
"must":[
{
"match":{
"accountId":"851512573210685440 851513094302625792"
}
},
{
"match":{
"status":"PENDING_CANCEL PENDING_REPLACE DORMANCY"
}
}
]
}
}
}
{
"query": {
"bool": {
"must": [
{
"match": {
"app_name": "st-global-service"
}
},
{
"match": {
"message": "/st-global/order/ticker/step"
}
}
]
}
}
}
filter 必须匹配AND
filter与must的区别:
1.must:match会为匹配到的每个记录打分,称作scoring,表示匹配程度,查询的结果按打分进行排序。
2.filter与must:match基本一致,唯一的区别是其结果不参与打分,相当于一个再过滤。
参考:https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-query.html
filter
中还可以再次进行bool
组合条件过滤
should 选择性匹配OR
应该满足should所列举的条件。OR
must_not 必须不能匹配NOT
必须不匹配must_not所列举的所有条件。NOT
聚合查询
Metric 聚合 - 计算字段值的 求和平均值等
Bucket 聚合 - 将字段值、范围、或者其它条件分组到Bucket中
Pipeline 聚合 - 从已聚合数据中进行聚合查询
aggs 聚合查询
aggregations
类似sql中的group by
GET xxx_index_name/_search
{
"size" : 0,
"aggs" : {
"xxxAgg" : { # 自定义的聚合名
"terms" : { # 划分桶的方式
"field" : "xxx" # 划分桶的字段
}
}
}
}
##分组后每组取第一条
GET xxx_index_name/_search
{
"query": {#查询条件},
"size": 0,
"aggs": {
"billIdAgg": {
"terms": {
"field": "billId",
"size": 100,
"min_doc_count": 1
},
"aggs": {
"top1": {
"top_hits": {
"size": 1,
"sort": [
{
"operateTime": {
"order": "desc"
}
}
]
}
}
}
}
}
}
sort 排序
order 升降序
GET xxx_index_name/_search
{
"query": {
"match": {
"xxx": "yyy"
}
},
"sort": [
{
"xxx": {
"": "asc/desc"
}
}
]
}
_score 得分
GET xxx_index_name/_search
{
"query": {
"match": {
"xxx": "yyy"
}
},
"sort": [
{
"price": {
"xxx": "asc/desc"
}
},
{
"_score": {
"xxx": "desc"
}
}
]
}
from+size 分页
from从第几条数据开始,size每页有多少数据
GET xxx_index_name/_search
{
"query": {
"match_all": {}
},
"from": 0,
"size": 5
}
问题
脑裂
Spring 整合
1、查询系统中所有的索引别名
public List<String> queryAllAlias() {
RestClient lowLevelClient = RestHighLevelClientHolder.get().getLowLevelClient();
Request request = new Request(HttpGet.METHOD_NAME, "_aliases");
Response response = lowLevelClient.performRequest(request);
String aliasString = EntityUtils.toString(response.getEntity());
Map<String, JSONObject> map = JSON.parseObject(aliasString, Map.class);
Set aliasSet = new HashSet();
for (JSONObject jsonObject :map.values()) {
aliasSet.addAll(jsonObject.getJSONObject("aliases").keySet());
}
List<String> result = new ArrayList<>(aliasSet);
Collections.sort(result);
return result;
}
2、根据索引别名查询关联的所有索引
public List<String> aliasIndex(Integer projectId, String aliasName) {
RestClient lowLevelClient = RestHighLevelClientHolder.get().getLowLevelClient();
Request request = new Request(HttpGet.METHOD_NAME, "_alias/" + aliasName);
Response response = lowLevelClient.performRequest(request);
String aliasString = EntityUtils.toString(response.getEntity());
Map<String, JSONObject> map = JSON.parseObject(aliasString, Map.class);
List<String> result = new ArrayList<>(map.keySet());
Collections.sort(result);
return result;
}
3、新增索引的索引别名
public void addAlias(String indexName, String aliasName) throws IOException {
IndicesClient indicesClient = RestHighLevelClientHolder.get().indices();
IndicesAliasesRequest.AliasActions aliasActions = IndicesAliasesRequest.AliasActions.add();
aliasActions.alias(aliasName);
aliasActions.index(indexName);
IndicesAliasesRequest indicesAliasesRequest = new IndicesAliasesRequest();
indicesAliasesRequest.addAliasAction(aliasActions);
indicesClient.updateAliases(indicesAliasesRequest, RequestOptions.DEFAULT);
}
4、删除索引的索引别名
public void deleteAlias(String indexName, String aliasName) throws IOException {
IndicesClient indicesClient = RestHighLevelClientHolder.get().indices();
IndicesAliasesRequest.AliasActions aliasActions = IndicesAliasesRequest.AliasActions.remove();
aliasActions.alias(aliasName);
aliasActions.index(indexName);
IndicesAliasesRequest indicesAliasesRequest = new IndicesAliasesRequest();
indicesAliasesRequest.addAliasAction(aliasActions);
indicesClient.updateAliases(indicesAliasesRequest, RequestOptions.DEFAULT);
}
5、聚合查询
public void deleteAlias(String indexName, String aliasName) throws IOException {
IndicesClient indicesClient = RestHighLevelClientHolder.get().indices();
IndicesAliasesRequest.AliasActions aliasActions = IndicesAliasesRequest.AliasActions.remove();
aliasActions.alias(aliasName);
aliasActions.index(indexName);
IndicesAliasesRequest indicesAliasesRequest = new IndicesAliasesRequest();
indicesAliasesRequest.addAliasAction(aliasActions);
indicesClient.updateAliases(indicesAliasesRequest, RequestOptions.DEFAULT);
}
QueryBuilders.rangeQuery
QueryBuilders是Elasticsearch提供的一个工具类,用于构建查询条件。它提供了一组方法,可以根据不同的需求来创建各种类型的查询。
以下是一些常用的QueryBuilders方法及其用途:
1. matchQuery(String fieldName, Object text):创建一个简单的全文匹配查询。它会在指定字段中查找与给定文本匹配的文档。
2. termQuery(String fieldName, Object value):创建一个项查询。它会在指定字段中查找与给定值完全匹配的文档。
3. rangeQuery(String fieldName):创建一个范围查询。它用于在指定字段中查找在一定范围内的值。
4. boolQuery():创建一个布尔查询。它可以通过组合多个查询条件来实现更复杂的查询逻辑,如must、must_not和should。
5. wildcardQuery(String fieldName, String wildcardPattern):创建一个通配符查询。它用于在指定字段中查找与通配符模式匹配的值。
6. matchPhraseQuery(String fieldName, Object text):创建一个短语匹配查询。它会在指定字段中查找包含给定短语的文档。
7. prefixQuery(String fieldName, String prefix):创建一个前缀查询。它用于在指定字段中查找以给定前缀开头的值。
8. fuzzyQuery(String fieldName, Object value):创建一个模糊查询。它用于在指定字段中查找与给定值相似的文档。
9. nestedQuery(String path, QueryBuilder queryBuilder, ScoreMode scoreMode):创建一个嵌套查询。它用于在嵌套的对象或文档中进行查询。
这些只是一些常用的QueryBuilders方法,还有其他更多的方法可用于构建不同类型的查询条件。根据具体的需求,可以选择合适的方法来构建自定义的查询。
安装ElasticSearch
下载地址:https://www.elastic.co/cn/downloads/elasticsearch
官网下载巨慢,可以使用华为云镜像
- ElasticSearch: https://mirrors.huaweicloud.com/elasticsearch/?C=N&O=D
- logstash: https://mirrors.huaweicloud.com/logstash/?C=N&O=D
- kibana: https://mirrors.huaweicloud.com/kibana/?C=N&O=D
- elasticsearch-analysis-ik: https://github.com/medcl/elasticsearch-analysis-ik/releases
- cerebro: https://github.com/lmenezes/cerebro/releases
Java环境:JDK8及以上。保证ElasticSearch的版本与Java的核心jar包版本对应!
目录 | 用途 | 文件 |
---|---|---|
bin | 启动文件 | |
config | 配置文件 | log4j2 日志配置文件 jvm.options java虚拟机相关的配置(默认启动占1g内存,内容不够需要自己调整) elasticsearch.yml elasticsearch的配置文件。默认9200端口!跨域! |
Lib | jar包 | |
modules | 功能模块目录 | |
plugins | 插件目录 | ik分词器 |
Solr
ElasticSearch vs Solr 总结
1、es基本是开箱即用(解压就可以用!) ,非常简单。Solr安装略微复杂一丢丢!
2、Solr 利用Zookeeper进行分布式管理,而Elasticsearch 自身带有分布式协调管理功能 。
3、Solr 支持更多格式的数据,比如JSON、XML、 CSV ,而Elasticsearch仅支持json文件格式。
4、Solr 官方提供的功能更多,而Elasticsearch本身更注重于核心功能,高级功能多有第三方插件提供,例如图形化界面需要kibana友好支撑
5、 Solr 查询快,但更新索引时慢(即插入删除慢) ,用于电商等查询多的应用;
- ES建立索引快(即查询慢) ,即实时性查询快,用于facebook新浪等搜索。
- Solr是传统搜索应用的有力解决方案,但Elasticsearch更适用于新兴的实时搜索应用。
6、Solr比较成熟,有一个更大,更成熟的用户、开发和贡献者社区,而Elasticsearch相对开发维护者较少,更新太快,学习使用成本较高。