zftang
作者zftang·2020-04-16 11:07
其它·小白一枚

elasticsearch与solr的比较

字数 8814阅读 910评论 0赞 0

elasticsearch 与 solr 的比较

— 环境搭建的区别**

elastic search:

  1. 要使用必须配置 Java_HOME 的环境变量

2.ik 分词器等高级功能由插件完成

  1. 自启动

Solr 是用 Java 编写、运行在 Servlet 容器(如 Apache Tomcat 或 Jetty )的一个独立的全文搜索服务器。

  1. 拷贝 solr war 包至 tomcat
  2. 拷贝日志 jar 包
  3. 配置 solrHome 和 solrCore\
  4. 在 war 包中 web.xml 中配置 solrhome 的位置
  5. 启动 tomcat

—客户端 API 的区别(如何进行文档的增删改查)

elastic search:

  1. 正常的编程顺序:创建索引–添加映射—储存数据(建立文档 json 数据),但是也可以直接创建文档,会自动创建索引,映射
  2. 单独使用要先创建搜索服务器 client 链接上服务器 ( QueryBuileders.queryStringQuery( 搜索内容 ) 匹配所有字段)

Client client = TransportClient.builder().build().addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("127.0.0.1"),9300));

· 1

  1. 索引的创建与删除
  2. //__创建索引
  3. client.admin().indices().prepareCreate("blog2").get();
  4. //__删除索引
  5. client.admin().indices().prepareDelete("blog2").get();

· 1

  1. 映射
  2. //__添加映射
  3. PutMappingRequest mapping = Requests.putMappingRequest("blog2").type("article").source(builder);_//_ ( builder 是映射 json 数据)
  4. client.admin().indices().putMapping(mapping).get();

· 1

  1. 文档
  2. //__创建文档 , 基于 xContentBuilder 的 json 数据
  3. client.prepareIndex("blog2", "article", "1").setSource(builder).get();
  4. //__创建文档 , 基于实体类
  5. client.prepareIndex("blog2", "article",article.getId().toString() ).setSource(mapper.writeValueAsString(article)).get();
  6. //__修改文档 , 也可以直接 client.update(new updateRequest())
  7. client.prepareUpdate("blog2", "article", article.getId().toString()).setDoc(mapper.writeValueAsString(article)).get();
  8. //__删 client.delete(new DeleteRequest)
  9. client.prepareDelete("blog2", "article", article.getId().toString()).get();
  10. //__查
  11. client.prepareIndex("blog2", "article",article.getId().toString()).setSource(mapper.writeValueAsString(article)).get();

· 1

Spring Data ElasticSearch:

  1. 编写 DAO 自动操作 elasticsearch 继承 ElasticsearchRepository 接口
  2. 通过 ElasticsearchTemplate 创建索引和添加映射 elasticsearchTemplate.createIndex(Article.class);
  3. 通过 service 层调用 save delete findAll 、 findOne 操作索引库 , 也可以分页查询

solr:

1.indexWriter.addDocument(document);

2.indexWriter.deleteDocuments(new Term( “ fileName ” , “文档” ));

3.indexWriter.updateDocument(new Term( “ fileName ” , ”问题” ), document); 先删后加

  1. TopDocs topDocs = indexSearcher.search(query, 10); indexReader, 传入不同的 query

QueryParser queryParser = new QueryParser( “ content ” , new IKAnalyzer());

—数据导入的区别

elasticsearch:

  1. 从数据库查找出来 ,wayBillIndexRepository.save() 方法自动同步

2.@Document(indexName= ” blog3 ” ,type= ” article ” )

@Id

@Field(index=FieldIndex.not_analyzed,store=true,type=FieldType.Integer)

solr:

  1. 在 web 管理工具上操作 , 必须保证每一个域 field 对象都已经在 schema.xml 配置
  2. 批量 :1. 导入 dataimport jar 包 数据库驱动 jar 包
  3. 配置 solrconfig.mxl 文件,添加一个 requestHandler 。
  4. 创建一个 data-config.xml ,保存到 collection1\conf\ 目录下 里面配置数据库信息 , 查询语句 , 以及数据库字段对应域对象
  5. 重启 tomcat , 执行 excute

— elastic search 里面,每个 document 可以指定一个 type :

@Document(indexName= ” bos ” , type= ” waybill ” )

type 是什么概念

文档类型 : 一个索引对象可以储存多个不同用途的 document 对象 ; 例如一个博客可以有文章和评论 , 文章和评论就是不同的文档类型 , 方便区分搜索 ;

— web 管理工具的区别

elasticsearch: EShead 插件访问 http://localhost:9200/_plugin/head/

solr: 基于 tomcat http://localhost:8080/solr/

— 性能、使用场景上的区别、优缺点(自己查资料总结)

  1. solr 查询快,但更新索引时慢(即插入删除慢),用于电商等查询多的应用;

2.ES 建立索引快(即查询慢),即实时性查询快,用于 facebook 新浪等搜索。

6.elasticsearch的一些其他问题

Elasticsearch是如何实现 Master 选举的?

Elasticsearch 的选举是 ZenDiscovery 模块负责的,主要包含 Ping (节点之间通过这个 RPC 来发现彼此)和 Unicast (单播模块包含一个主机列表以控制哪些节点需要 ping 通)这两部分;

对所有可以成为 master 的节点( node.master: true )根据 nodeId 字典排序,每次选举每个节点都把自己所知道节点排一次序,然后选出第一个(第 0 位)节点,暂且认为它是 master 节点。

如果对某个节点的投票数达到一定的值(可以成为 master 节点数 n/2+1 )并且该节点自己也选举自己,那这个节点就是 master 。否则重新选举一直到满足上述条件。

补充: master 节点的职责主要包括集群、节点和索引的管理,不负责文档级别的管理; data 节点可以关闭 http 功能。

Elasticsearch 中的节点(比如共 20 个),其中的 10 个选了一个 master ,另外 10 个选了另一个 master ,怎么办?

当集群 master 候选数量不小于 3 个时,可以通过设置最少投票通过数量( discovery.zen.minimum_master_nodes )超过所有候选节点一半以上来解决脑裂问题;

当候选数量为两个时,只能修改为唯一的一个 master 候选,其他作为 data 节点,避免脑裂问题。

客户端在和集群连接时,如何选择特定的节点执行请求的?

TransportClient 利用 transport 模块远程连接一个 elasticsearch 集群。它并不加入到集群中,只是简单的获得一个或者多个初始化的 transport 地址,并以 轮询 的方式与这些地址进行通信。

详细描述一下 Elasticsearch 索引文档的过程。

协调节点默认使用文档 ID 参与计算(也支持通过 routing ),以便为路由提供合适的分片。 shard = hash(document_id) % (num_of_primary_shards)

当分片所在的节点接收到来自协调节点的请求后,会将请求写入到 Memory Buffer ,然后定时(默认是每隔 1 秒)写入到 Filesystem Cache ,这个从 Momery Buffer 到 Filesystem Cache 的过程就叫做 refresh ;

当然在某些情况下,存在 Momery Buffer 和 Filesystem Cache 的数据可能会丢失, ES 是通过 translog 的机制来保证数据的可靠性的。其实现机制是接收到请求后,同时也会写入到 translog 中,当 Filesystem cache 中的数据写入到磁盘中时,才会清除掉,这个过程叫做 flush ;

在 flush 过程中,内存中的缓冲将被清除,内容被写入一个新段,段的 fsync 将创建一个新的提交点,并将内容刷新到磁盘,旧的 translog 将被删除并开始一个新的 translog 。

flush 触发的时机是定时触发(默认 30 分钟)或者 translog 变得太大(默认为 512M )时;

详细描述一下 Elasticsearch 更新和删除文档的过程。

删除和更新也都是写操作,但是 Elasticsearch 中的文档是不可变的,因此不能被删除或者改动以展示其变更;

磁盘上的每个段都有一个相应的 .del 文件。当删除请求发送后,文档并没有真的被删除,而是在 .del 文件中被标记为删除。该文档依然能匹配查询,但是会在结果中被过滤掉。当段合并时,在 .del 文件中被标记为删除的文档将不会被写入新段。

在新的文档被创建时, Elasticsearch 会为该文档指定一个版本号,当执行更新时,旧版本的文档在 .del 文件中被标记为删除,新版本的文档被索引到一个新段。旧版本的文档依然能匹配查询,但是会在结果中被过滤掉。

详细描述一下 Elasticsearch 搜索的过程。

搜索被执行成一个两阶段过程,我们称之为 Query Then Fetch ;

在初始查询阶段时,查询会广播到索引中每一个分片拷贝(主分片或者副本分片)。 每个分片在本地执行搜索并构建一个匹配文档的大小为 from + size 的优先队列。 PS :在搜索的时候是会查询 Filesystem Cache 的,但是有部分数据还在 Memory Buffer ,所以搜索是近实时的。

每个分片返回各自优先队列中 所有文档的 ID 和排序值 给协调节点,它合并这些值到自己的优先队列中来产生一个全局排序后的结果列表。

接下来就是 取回阶段,协调节点辨别出哪些文档需要被取回并向相关的分片提交多个 GET 请求。每个分片加载并 丰富 文档,如果有需要的话,接着返回文档给协调节点。一旦所有的文档都被取回了,协调节点返回结果给客户端。

补充: Query Then Fetch 的搜索类型在文档相关性打分的时候参考的是本分片的数据,这样在文档数量较少的时候可能不够准确, DFS Query Then Fetch 增加了一个预查询的处理,询问 Term 和 Document frequency ,这个评分更准确,但是性能会变差。

对于 GC 方面,在使用 Elasticsearch 时要注意什么?

倒排词典的索引需要常驻内存,无法 GC ,需要监控 data node 上 segment memory 增长趋势。

各类缓存, field cache, filter cache, indexing cache, bulk queue 等等,要设置合理的大小,并且要应该根据最坏的情况来看 heap 是否够用,也就是各类缓存全部占满的时候,还有 heap 空间可以分配给其他任务吗?避免采用 clear cache 等“自欺欺人”的方式来释放内存。

避免返回大量结果集的搜索与聚合。确实需要大量拉取数据的场景,可以采用 scan & scroll api 来实现。

cluster stats 驻留内存并无法水平扩展,超大规模集群可以考虑分拆成多个集群通过 tribe node 连接。

想知道 heap 够不够,必须结合实际应用场景,并对集群的 heap 使用情况做持续的监控。

Elasticsearch对于大数据量(上亿量级)的聚合如何实现?

Elasticsearch 提供的首个近似聚合是 cardinality 度量。它提供一个字段的基数,即该字段的 distinct 或者 unique 值的数目。它是基于 HLL 算法的。 HLL 会先对我们的输入作哈希运算,然后根据哈希运算的结果中的 bits 做概率估算从而得到基数。其特点是:可配置的精度,用来控制内存的使用(更精确 = 更多内存);小的数据集精度是非常高的;我们可以通过配置参数,来设置去重需要的固定内存使用量。无论数千还是数十亿的唯一值,内存使用量只与你配置的精确度相关。

在并发情况下, Elasticsearch 如果保证读写一致?

可以通过版本号使用乐观并发控制,以确保新版本不会被旧版本覆盖,由应用层来处理具体的冲突;

另外对于写操作,一致性级别支持 quorum/one/all ,默认为 quorum ,即只有当大多数分片可用时才允许写操作。但即使大多数可用,也可能存在因为网络等原因导致写入副本失败,这样该副本被认为故障,分片将会在一个不同的节点上重建。

对于读操作,可以设置 replication 为 sync( 默认 ) ,这使得操作在主分片和副本分片都完成后才会返回;如果设置 replication 为 async 时,也可以通过设置搜索请求参数 _preference 为 primary 来查询主分片,确保文档是最新版本。

如何监控 Elasticsearch 集群状态?

Marvel 让你可以很简单的通过 Kibana 监控 Elasticsearch 。你可以实时查看你的集群健康状态和性能,也可以分析过去的集群、索引和节点指标。

介绍一下你们的个性化搜索方案?

SEE 基于 word2vec 和 Elasticsearch 实现个性化搜索

是否了解字典树?

常用字典数据结构如下所示:

Trie 的核心思想是空间换时间,利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。它有 3 个基本性质:

根节点不包含字符,除根节点外每一个节点都只包含一个字符。

从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。

每个节点的所有子节点包含的字符都不相同。

可以看到, trie 树每一层的节点数是 26^i 级别的。所以为了节省空间,我们还可以用动态链表,或者用数组来模拟动态。而空间的花费,不会超过单词数×单词长度。

实现:对每个结点开一个字母集大小的数组,每个结点挂一个链表,使用左儿子右兄弟表示法记录这棵树;

对于中文的字典树,每个节点的子节点用一个哈希表存储,这样就不用浪费太大的空间,而且查询速度上可以保留哈希的复杂度 O(1) 。

拼写纠错是如何实现的?

拼写纠错是基于编辑距离来实现;编辑距离是一种标准的方法,它用来表示经过插入、删除和替换操作从一个字符串转换到另外一个字符串的最小操作步数;

编辑距离的计算过程:比如要计算 batyu 和 beauty 的编辑距离,先创建一个 7 × 8 的表( batyu 长度为 5 , coffee 长度为 6 ,各加 2 ),接着,在如下位置填入黑色数字。其他格的计算过程是取以下三个值的最小值:

如果最上方的字符等于最左方的字符,则为左上方的数字。否则为左上方的数字 +1 。(对于 3,3 来说为 0 )左方数字 +1 (对于 3,3 格来说为 2 )上方数字 +1 (对于 3,3 格来说为 2 )最终取右下角的值即为编辑距离的值 3 。

对于拼写纠错,我们考虑构造一个度量空间( Metric Space ),该空间内任何关系满足以下三条基本条件:

d(x,y) = 0 – 假如 x 与 y 的距离为 0 ,则 x=y

d(x,y) = d(y,x) – x 到 y 的距离等同于 y 到 x 的距离

d(x,y) + d(y,z) >= d(x,z) – 三角不等式

根据三角不等式,则满足与 query 距离在 n 范围内的另一个字符转 B ,其与 A 的距离最大为 d+n ,最小为 d-n 。

BK 树的构造就过程如下:每个节点有任意个子节点,每条边有个值表示编辑距离。所有子节点到父节点的边上标注 n 表示编辑距离恰好为 n 。比如,我们有棵树父节点是” book ”和两个子节点” cake ”和” books ”,” book ”到” books ”的边标号 1 ,” book ”到” cake ”的边上标号 4 。从字典里构造好树后,无论何时你想插入新单词时,计算该单词与根节点的编辑距离,并且查找数值为 d(neweord, root) 的边。递归得与各子节点进行比较,直到没有子节点,你就可以创建新的子节点并将新单词保存在那。比如,插入” boo ”到刚才上述例子的树中,我们先检查根节点,查找 d( “ book ” , “ boo ” ) = 1 的边,然后检查标号为 1 的边的子节点,得到单词” books ”。我们再计算距离 d( “ books ” , “ boo ” )=2 ,则将新单词插在” books ”之后,边标号为 2 。

查询相似词如下:计算单词与根节点的编辑距离 d ,然后递归查找每个子节点标号为 d-n 到 d+n (包含)的边。假如被检查的节点与搜索单词的距离 d 小于 n ,则返回该节点并继续查询。比如输入 cape 且最大容忍距离为 1 ,则先计算和根的编辑距离 d( “ book ” , “ cape ” )=4 ,然后接着找和根节点之间编辑距离为 3 到 5 的,这个就找到了 cake 这个节点,计算 d( “ cake ” , “ cape ” )=1 ,满足条件所以返回 cake ,然后再找和 cake 节点编辑距离是 0 到 2 的,分别找到 cape 和 cart 节点,这样就得到 cape 这个满足条件的结果。

7.elasticsearch的使用案例

( 1 )维基百科,类似百度百科,牙膏,牙膏的维基百科,全文检索,高亮,搜索推荐

( 2 ) The Guardian (国外新闻网站),类似搜狐新闻,用户行为日志(点击,浏览,收藏,评论) + 社交网络

数据(对某某新闻的相关看法),数据分析,给到每篇新闻文章的作者,让他知道他的文章的公众反馈(好,

坏,热门,垃圾,鄙视,崇拜)

( 3 ) Stack Overflow (国外的程序异常讨论论坛), IT 问题,程序的报错,提交上去,有人会跟你讨论和回答,全文检索,搜索相关问题和答案,程序报错了,就会将报错信息粘贴到里面去,搜索有没有对应的答案

( 4 ) GitHub (开源代码管理),搜索上千亿行代码

( 5 )电商网站,检索商品

( 6 )日志数据分析, logstash 采集日志, ES 进行复杂的数据分析( ELK 技术, elasticsearch+logstash+kibana )

( 7 )商品价格监控网站,用户设定某商品的价格阈值,当低于该阈值的时候,发送通知消息给用户,比如说订阅牙膏的监控,如果高露洁牙膏的家庭套装低于 50 块钱,就通知我,我就去买

( 8 ) BI 系统,商业智能, Business Intelligence 。比如说有个大型商场集团, BI ,分析一下某某区域最近 3 年的用户消费金额的趋势以及用户群体的组成构成,产出相关的数张报表, ** 区,最近 3 年,每年消费金额呈现 100% 的增长,而且用户群体 85% 是高级白领,开一个新商场。 ES 执行数据分析和挖掘, Kibana 进行数据可视化

( 9 )国内:站内搜索(电商,招聘,门户,等等), IT 系统搜索( OA , CRM , ERP ,等等),数据分析( ES 热门
的一个使用场景)

如果觉得我的文章对您有用,请点赞。您的支持将鼓励我继续创作!

0

添加新评论0 条评论

Ctrl+Enter 发表

作者其他文章

相关文章

相关问题

相关资料

X社区推广