zoukankan      html  css  js  c++  java
  • Solr的入门知识

     

    一.Solr的简介

          Solr 是Apache下的一个顶级开源项目,采用Java开发,它是基于Lucene的全文搜索服务。Solr可以独立运行在Jetty、Tomcat等这些Servlet容器中。都是Web服务器,Servlet容器,报文 ,JSON 格式字符串, XML格式字符串。Solr是一个可以独立运行的搜索服务器,使用solr进行全文检索服务的话,只需要通过http请求访问该服务器即可。

    使用Solr 进行创建索引和搜索索引的实现方法很简单,如下:

    • 创建索引:客户端(可以是浏览器可以是Java程序)用 POST 方法向 Solr 服务器发送一个描述 Field 及其内容的 XML 文档,Solr服务器根据xml文档添加、删除、更新索引 。 
    • 搜索索引:客户端(可以是浏览器可以是Java程序)用 GET方法向 Solr 服务器发送请求,然后对 Solr服务器返回Xml、json等格式的查询结果进行解析。Solr不提供构建页面UI的功能。Solr提供了一个管理界面,通过管理界面可以查询Solr的配置和运行情况。

    二.Solr和Lucene的区别

          Lucene是一个开放源代码的全文检索引擎工具包,它不是一个完整的全文检索应用。Lucene仅提供了完整的查询引擎和索引引擎,目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能,或者以Lucene为基础构建全文检索应用。

          Solr的目标是打造一款企业级的搜索引擎系统,它是基于Lucene一个搜索引擎服务,可以独立运行,通过Solr可以非常快速的构建企业的搜索引擎,通过Solr也可以高效的完成站内搜索功能。

    三.Solr的单机与集群概念

    1.Solr的单机版

           概念:HttpSolrServer

    2.Solr的集群版

            概念:SolrCloud(solr 云)是Solr提供的分布式搜索方案,当你需要大规模,容错,分布式索引和检索能力时使用 SolrCloud。当一个系统的索引数据量少的时候是不需要使用SolrCloud的,当索引量很大,搜索请求并发很高,这时需要使用SolrCloud来满足这些需求

            结构:SolrCloud为了降低单机的处理压力,需要由多台服务器共同来完成索引和搜索任务。实现的思路是将索引数据进行Shard(分片)拆分,每个分片由多台的服务器共同完成,当一个索引或搜索请求过来时会分别从不同的Shard的服务器中操作索引。SolrCloud需要Solr基于Zookeeper部署,Zookeeper是一个集群管理软件,由于SolrCloud需要由多台服务器组成,由zookeeper来进行协调管理。

    一个collection可以把数据(索引文件)拆分成多份,放进几个不同的shard中,一个shard的数据可以有多个备份(replica)。一个shard的多个replica中会有一个leader,由选举程序推选出来。一个replica相当于一个core。
     
    这个功能的主要特性是:
    • 整个集群的配置信息可以集中配置
    • 对于搜索自动负载均衡、出现故障时可以自动切换
    • 集成了ZooKeeper,负责集群的协调和配置

     
    如上图,一个collection(collection1)被拆分到两个不同的shard中,而每个shard都有两个服务器(node)提供负载均衡和遇错切换的服务。这个分布式的结构是由ZooKeeper负责管理的。那些node中,实心圆圈的就是leader。
     
    相关概念:
    • HA:High Availability
    • Node:一个服务器、或虚拟服务器节点,每个node对应一个port向外提供服务。对应于一个JVM。
    • Collection:一个SolrCloud实例,负责对一批数据建立一个索引,并提供基于这个索引的搜索服务
    • Shard:一个SolrCloud中的索引可以被拆分存放到多个shard中
    • Replica:一个shard中的数据,可以有多个副本,就是Replica,其中有一个被推选出来的leader
    • Core:负责处理一个Replica,跟一个node对应
    • Cluster:由ZooKeeper管理的多个Node的集合,对solr的请求可以发送给一个cluster
    Shard的数量决定了索引是如果被拆分的,所以,当一个cluster初始化完成之后,shard的数量是不能改的。
    创建一个新的core并加入到一个Collection和shard中:
     
    Shard的迁移:
    如果原来只有一个机器、或只有少量机器,可以先规划好shard的数量并启动,然后等有新的机器之后,在新的机器中为某个shard启动一个新的replica,然后把原来的shard移除,这样ZooKeeper就会把新的replica提升为这个shard的leader了。
     
    Leader和Replica:
    如果Solr启动的时候,参数numShards=2,那么前两个启动的node就是leader,分别服务于这两个shard,第三个和之后启动的node就是replica,他们会依次按照那两个leader加入cluster的顺序分配给那两个leader(使用round-robin的方式)。也可以在启动node的时候使用shardId参数直接把这个node分配给某个shard。当solr重启的时候,所有的node还是归属到重启之前所归属的shard,同个shard中先启动的node就是leader(first come first served)。
    当一个leader无法工作的时候,这个shard中的某一个replica会被自动推选为leader。在Solr Admin UI界面中,Cloud菜单里面可以看到哪个是Leader(实心圆圈者)。
     
    新的文档可以被送往任何一个node,SolrCloud会自动把它们分配到合适的shard中:
    • 如果文档被送到一个replica中,那么这个replica会把这些文档发送给这个shard的leader
    • 当一个leader接收到文档的时候,SolrCloud会决定这些文档应该分配到哪个shard,然后把它们发生给这个shard的leader、建立索引、并把索引发送给这个shard中所有的replica
    添加shard:
    如果需要加多一个shard,可以使用Collections API,创建两个新的shard,再把现有shard中的索引分配到这两个新Shard中。旧的shard需要手动删掉。
    package com.xyg.solrj;
    
    import java.util.List;
    import java.util.Map;
    import org.apache.solr.client.solrj.SolrQuery;
    import org.apache.solr.client.solrj.SolrQuery.ORDER;
    import org.apache.solr.client.solrj.SolrServer;
    import org.apache.solr.client.solrj.impl.HttpSolrServer;
    import org.apache.solr.client.solrj.response.QueryResponse;
    import org.apache.solr.common.SolrDocument;
    import org.apache.solr.common.SolrDocumentList;
    import org.apache.solr.common.SolrInputDocument;
    import org.junit.Test;
    
    /**
     * <p>Title:SolrjDemo</p>
     * @Description:solrj的入门程序
     * @Param:
     * @Return:
     * @Author:Administrator
     * @Date:2017年11月3日上午12:32:42
     */
    public class SolrjDemo {
        //添加  修改
        @Test
        public void testCreateAndUpdateIndex() throws Exception {
            // 1. 创建HttpSolrServer对象
            // 设置solr服务接口,浏览器客户端地址http://127.0.0.1:8080/solr/#/
            String baseURL = "http://127.0.0.1:8080/solr";
            //String baseURL = "http://localhost:8080/solr/collection2";
            SolrServer solrServer = new HttpSolrServer(baseURL);
            // 2. 创建SolrInputDocument对象
            SolrInputDocument document = new SolrInputDocument();
            document.addField("id", "100");
            document.addField("name", "Hello world!");
            // 3. 把SolrInputDocument对象添加到索引库中
            solrServer.add(document); //httpSolrServer.add(document,1000);
            // 4. 提交
            solrServer.commit();
        }    
        //删除
        @Test
        public void testDeleteIndex() throws Exception {
            String baseURL = "http://127.0.0.1:8080/solr";        
            SolrServer  solrServer = new HttpSolrServer(baseURL);
            // 根据id删除索引数据
            //solrServer.deleteById("100");
            // 根据条件删除(如果是*:*就表示全部删除,慎用)
            //solrServer.deleteByQuery("name:Hello");
            solrServer.deleteByQuery("*:*");  //删除所有        
            solrServer.commit();  // 提交
        }
        //查询
        @Test
        public void testSearchIndex1() throws Exception {
            String baseURL = "http://127.0.0.1:8080/solr";        
            SolrServer  solrServer = new HttpSolrServer(baseURL);
            // 创建搜索对象
            SolrQuery query = new SolrQuery();
            // 设置搜索条件
            query.setQuery("*:*");
            // 发起搜索请求
            QueryResponse response = solrServer.query(query);
            // 处理搜索结果
            SolrDocumentList docs = response.getResults();
            System.out.println("搜索到的结果总数:" + docs.getNumFound());
            // 遍历搜索结果
            for (SolrDocument doc : docs) {
            System.out.println("----------------------------------------------------");
            System.out.println("id:" + doc.get("id"));
            System.out.println("name:" + doc.get("name"));
            }
        }        
        //复杂查询索引
        @Test
        public void queryIndex2() throws Exception {
            //创建连接
            SolrServer solrServer = new HttpSolrServer("http://localhost:8080/solr");
            //创建一个query对象
            SolrQuery solrQuery = new SolrQuery();
            //设置关键词查询条件
            solrQuery.setQuery("钻石");   //solrQuery.set("q","钻石");        
            //过滤条件
            solrQuery.setFilterQueries("product_catalog_name:幽默杂货");
            //排序条件
            solrQuery.setSort("product_price", ORDER.asc);
            //分页处理
            solrQuery.setStart(0);
            solrQuery.setRows(10);
            //结果中域的列表        solrQuery.setFields("id","product_name","product_price","product_catalog_name","product_picture");
            //设置默认搜索域
            solrQuery.set("df", "product_keywords");
            //高亮显示
            solrQuery.setHighlight(true);
            //高亮显示的域
            solrQuery.addHighlightField("product_name");
            //高亮显示的前缀
            solrQuery.setHighlightSimplePre("<font color='red'>");
            //高亮显示的后缀
            solrQuery.setHighlightSimplePost("</font>");
            //执行查询
            QueryResponse queryResponse = solrServer.query(solrQuery);
            //取查询结果
            SolrDocumentList solrDocumentList = queryResponse.getResults();
            //共查询到商品数量
            System.out.println("共查询到商品数量:" + solrDocumentList.getNumFound());
            //遍历查询的结果
            for (SolrDocument solrDocument : solrDocumentList) {
                System.out.println(solrDocument.get("id"));
                //取高亮显示
                String productName = "";
                Map<String, Map<String, List<String>>> highlighting = queryResponse.getHighlighting();
                List<String> list = highlighting.get(solrDocument.get("id")).get("product_name");
                //判断是否有高亮内容
                if (null != list) {
                    productName = list.get(0);
                } else {
                    productName = (String) solrDocument.get("product_name");
                }                
                System.out.println(productName);
                System.out.println(solrDocument.get("product_price"));           
    System.out.println(solrDocument.get("product_catalog_name")); System.out.println(solrDocument.get("product_picture")); } } }
  • 相关阅读:
    Combine 框架,从0到1 —— 4.在 Combine 中使用计时器
    Combine 框架,从0到1 —— 4.在 Combine 中使用通知
    Combine 框架,从0到1 —— 3.使用 Subscriber 控制发布速度
    Combine 框架,从0到1 —— 2.通过 ConnectablePublisher 控制何时发布
    使用 Swift Package Manager 集成依赖库
    iOS 高效灵活地配置可复用视图组件的主题
    构建个人博客网站(基于Python Flask)
    Swift dynamic关键字
    Swift @objcMembers
    仅用递归函数操作逆序一个栈(Swift 4)
  • 原文地址:https://www.cnblogs.com/frankdeng/p/9017324.html
Copyright © 2011-2022 走看看