zoukankan      html  css  js  c++  java
  • solrj-WiKi

      solrj是一个访问solr的客户端,它提供了一个接口,用于添加、更新、删除索引数据.

    solrj跨版本兼容

       solrj一般保持向后兼容,所以你可以使用新版本的solrj访问老版本的solr服务,也可以使用老版本的solrj访问新版本的solr.

      如果混合了1.x和以后的主版本,那么必须设置响应解析器XML:

    server.setParser(new XMLResponseParser());

       3.x和4.x或者以后的版本混合的solr工作正常,只要不更改这个请求writer为二进制格式.

      有一个例外情况javabin格式,兼容方式在主版本之间已经改变.

    设置类路径

      solrj需要的最小jar包集合:

      /dist:

        apache-solr-solrj-*.jar

      /dist/solrj-lib:

      • commons-codec-1.3.jar
      • commons-httpclient-3.1.jar
      • commons-io-1.4.jar
      • jcl-over-slf4j-1.5.5.jar
      • slf4j-api-1.5.5.jar

      /lib:

         slf4j-jdk14-1.5.5.jar

    Maven

      在官方maven仓库中solrj是可以使用的,加入一下依赖到pom.xml中:

    <dependency>
        <artifactId>solr-solrj</artifactId>
        <groupId>org.apache.solr</groupId>
        <version>4.7.2</version>
        <type>jar</type>
        <scope>compile</scope>
    </dependency>

      如果使用EmbeddedSolrServer,加入一下依赖:

    <dependency>
        <artifactId>solr-core</artifactId>
        <groupId>org.apache.solr</groupId>
        <version>4.7.2</version>
        <type>jar</type>
        <scope>compile</scope>
    </dependency>

       同样,如果使用了EmbeddedSolrServer,注意Servlet API的依赖:

    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>3.0</version>
    </dependency>

       如果碰到NoClassDefFoundError 异常,加入一下依赖:

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-simple</artifactId>
        <version>1.6.6</version>
    </dependency>

     HttpSolrServer

      HttpSolrServer使用Apache Commons HTTP Client连接solr. 注意:在solr4.0中, CommonsHttpSolrServer 改成了 HttpSolrServer ,StreamingUpdateSolrServer 改成了ConcurrentUpdateSolrServer.

            String url = "http://localhost:8983/solr";
            /*
             * HttpSolrServer线程安全,如果使用下面构造器,必须对所有的请求重用相同的实例.如果实例在运行中创建的,它可能会导致连接泄漏.
             * 推荐的做法就是保持每个solr服务url的HttpSolrServer的静态实例,所有的请求都共享这个实例.
             * 参考https://issues.apache.org/jira/browse/SOLR-861查看更多细节.
             */
            SolrServer server = new HttpSolrServer(url);

    具体可以参考:HttpSolrServer-采用静态工厂方法,创建HttpSolrServer单实例.如果你有更好的方法,可以回复一下,互相交流.

    修改其他的Connection设置:

          String url = "http://localhost:8983/solr";
            HttpSolrServer server = new HttpSolrServer(url);
            server.setMaxRetries(1); // defaults to 0. > 1 not recommended.
            server.setConnectionTimeout(5000); // 5 seconds to establish TCP
            // 下面的设置被完整的提供,它们一般不是必须选择的,最好是在查阅java文档之后来确认它们是否必须使用.
            server.setSoTimeout(1000); // socket read timeout
            server.setDefaultMaxConnectionsPerHost(100);
            server.setMaxTotalConnections(100);
            server.setFollowRedirects(false); // defaults to false
            // 允许压缩默认为false.
            // Server side must support gzip or deflate for this to have any effect.
            server.setAllowCompression(true);

     使用

       首先创建一个服务的实例:

     SolrServer server = new HttpSolrServer("http://HOST:8983/solr/");

       删除所有索引数据:

    server.deleteByQuery( "*:*" );

     构造一个document:

        SolrInputDocument doc1 = new SolrInputDocument();
        doc1.addField( "id", "id1", 1.0f );
        doc1.addField( "name", "doc1", 1.0f );
        doc1.addField( "price", 10 );

       构造另外一个document,最好是批量处理document,因为每次调用solrServer,就是一次http调用.

        SolrInputDocument doc2 = new SolrInputDocument();
        doc2.addField( "id", "id2", 1.0f );
        doc2.addField( "name", "doc2", 1.0f );
        doc2.addField( "price", 20 );

       创建一个document的集合:

        Collection<SolrInputDocument> docs = new ArrayList<SolrInputDocument>();
        docs.add( doc1 );
        docs.add( doc2 );

       添加集合到solrServer,并提交.

     server.add( docs );
    server.commit()

      为了在添加documents之后立刻提交,可以这样使用:

      UpdateRequest req = new UpdateRequest();
      req.setAction( UpdateRequest.ACTION.COMMIT, false, false );
      req.add( docs );
      UpdateResponse rsp = req.process( server );

    更新文档流(streamimg documents)

      大多数情况下,ConcurrentUpdateSolrServer就可以满足需要.作为一种选择,下面给出的解决方法可以应用

      这是一个在一个请求里更新所有文档的最优化的方案:

      

    HttpSolrServer server = new HttpSolrServer();
    Iterator<SolrInputDocument> iter = new Iterator<SolrInputDocument>(){
         public boolean hasNext() {
            boolean result ;
            // set the result to true false to say if you have more documensts
            return result;
          }
    
          public SolrInputDocument next() {
            SolrInputDocument result = null;
            // construct a new document here and set it to result
            return result;
          }
    };
    server.add(iter);

    也可以使用addBeans(Iterator<?> beansIter)来索引对象.

    直接添加POJO到Solr

      使用注解创建一个java bean.@Field可以用到字段(field)或者是方法(setter)上.如果索引字段名称和bean的字段名称不相同,可以使用别名来做一个映射,

    import org.apache.solr.client.solrj.beans.Field;
    
     public class Item {
        @Field
        String id;
    
        @Field("cat")
        String[] categories;
    
        @Field
        List<String> features;
    
      }

      或者是在setter方法中添加:

        @Field("cat")
       public void setCategory(String[] c){
           this.categories = c;
       }

      获取SolrServer实例:

    SolrServer server = getSolrServer();

      创建bean实例:

        Item item = new Item();
        item.id = "one";
        item.categories =  new String[] { "aaa", "bbb", "ccc" };

      添加到solr:

    server.addBean(item);

      添加bean集合:

      List<Item> beans ;
      //add Item objects to the list
      server.addBeans(beans);

    solr事务处理

      solr在服务器级别实现事务处理.也就是说每次commit, optimize, or rollback都应用到了所有的请求中.更新solr最恰当的方式就是使用单独的进程来处理,以避免在提交或者是回滚时产生的竞争冲突.同样,最好是使用批处理来索引,因为提交和优化都是高消耗的程序.

    读数据--数据库

    import java.io.IOException;
    import java.net.MalformedURLException;
    import java.sql.ResultSet;
    import java.sql.ResultSetMetaData;
    import java.sql.SQLException;
    import java.sql.Types;
    import java.util.ArrayList;
    import java.util.Collection;
    
    import org.apache.solr.client.solrj.SolrServerException;
    import org.apache.solr.client.solrj.impl.HttpSolrServer;
    import org.apache.solr.common.SolrInputDocument;
    
    public class Test
    {
        private static int fetchSize = 1000;
        private static String url = "http://localhost:8983/solr/core1/";
        private static HttpSolrServer solrCore;
    
        public Test() throws MalformedURLException
        {
             solrCore = new HttpSolrServer(url);
        }
    
        /**
         * Takes an SQL ResultSet and adds the documents to solr. Does it in batches
         * of fetchSize.
         * 
         * @param rs
         *            A ResultSet from the database.
         * @return The number of documents added to solr.
         * @throws SQLException
         * @throws SolrServerException
         * @throws IOException
         */
        public long addResultSet(ResultSet rs) throws SQLException,
                SolrServerException, IOException
        {
            long count = 0;
            int innerCount = 0;
            Collection<SolrInputDocument> docs = new ArrayList<SolrInputDocument>();
            ResultSetMetaData rsm = rs.getMetaData();
            int numColumns = rsm.getColumnCount();
            String[] colNames = new String[numColumns + 1];
    
            /**
             * JDBC numbers the columns starting at 1, so the normal java convention
             * of starting at zero won't work.
             */
            for (int i = 1; i < (numColumns + 1); i++)
            {
                colNames[i] = rsm.getColumnName(i);
                /**
                 * If there are fields that you want to handle manually, check for
                 * them here and change that entry in colNames to null. This will
                 * cause the loop in the next section to skip that database column.
                 */
                // //Example:
                // if (rsm.getColumnName(i) == "db_id")
                // {
                // colNames[i] = null;
                // }
            }
    
            while (rs.next())
            {
                count++;
                innerCount++;
    
                SolrInputDocument doc = new SolrInputDocument();
    
                /**
                 * At this point, take care of manual document field assignments for
                 * which you previously assigned the colNames entry to null.
                 */
                // //Example:
                // doc.addField("solr_db_id", rs.getLong("db_id"));
    
                for (int j = 1; j < (numColumns + 1); j++)
                {
                    if (colNames[j] != null)
                    {
                        Object f;
                        switch (rsm.getColumnType(j))
                        {
                            case Types.BIGINT:
                            {
                                f = rs.getLong(j);
                                break;
                            }
                            case Types.INTEGER:
                            {
                                f = rs.getInt(j);
                                break;
                            }
                            case Types.DATE:
                            {
                                f = rs.getDate(j);
                                break;
                            }
                            case Types.FLOAT:
                            {
                                f = rs.getFloat(j);
                                break;
                            }
                            case Types.DOUBLE:
                            {
                                f = rs.getDouble(j);
                                break;
                            }
                            case Types.TIME:
                            {
                                f = rs.getDate(j);
                                break;
                            }
                            case Types.BOOLEAN:
                            {
                                f = rs.getBoolean(j);
                                break;
                            }
                            default:
                            {
                                f = rs.getString(j);
                            }
                        }
                        doc.addField(colNames[j], f);
                    }
                }
                docs.add(doc);
    
                /**
                 * When we reach fetchSize, index the documents and reset the inner
                 * counter.
                 */
                if (innerCount == fetchSize)
                {
                    solrCore.add(docs);
                    docs.clear();
                    innerCount = 0;
                }
            }
    
            /**
             * If the outer loop ended before the inner loop reset, index the
             * remaining documents.
             */
            if (innerCount != 0)
            {
                solrCore.add(docs);
            }
            return count;
        }
    }
    View Code

     设置RequestWriter

      solrj允许使用XML和二进制两种格式上传内容,默认设置是XML.下面使用的是二进制上传内容,solrj获取结果采用相同的格式.并且这样极大的提高了性能,因为它减少了XML编组开销.

    server.setRequestWriter(new BinaryRequestWriter());

      注意:确定solrconfig.xml中同样开启"BinaryUpdateRequestHandler"的功能:

    <requestHandler name="/update/javabin" class="solr.BinaryUpdateRequestHandler" />

     Solr中读取查询内容

      获取一个solrServer实例:

    SolrServer server = getSolrServer();

       构造SolrQuery:

        SolrQuery query = new SolrQuery();
        query.setQuery( "*:*" );
        query.addSortField( "price", SolrQuery.ORDER.asc );

       执行查询:

        QueryResponse rsp = server.query( query );

       获取结果:

       SolrDocumentList docs = rsp.getResults();

       获取bean对象的结果集,bean类必须采用注解.

    List<Item> beans = rsp.getBeans(Item.class);

     高级使用方式

      SolrJ提供了一个API来创建查询,而不是手工编码查询.下面是一个分面查询的例子:

      SolrServer server = getSolrServer();
      SolrQuery solrQuery = new  SolrQuery().
                    setQuery("ipod").
                    setFacet(true).
                    setFacetMinCount(1).
                    setFacetLimit(8).
                    addFacetField("category").
                    addFacetField("inStock");
      QueryResponse rsp = server.query(solrQuery);

     高亮--Highlighting

       设置高亮参数的方式和其他常用参数的设置方式一样:

        SolrQuery query = new SolrQuery();
        query.setQuery("foo");
    
        query.setHighlight(true).setHighlightSnippets(1); //set other params as needed
        query.setParam("hl.fl", "content");
    
        QueryResponse queryResponse = getSolrServer().query(query);

      这样取回高亮结果集:

        Iterator<SolrDocument> iter = queryResponse.getResults().iterator();
    
        while (iter.hasNext()) {
          SolrDocument resultDoc = iter.next();
    
          String content = (String) resultDoc.getFieldValue("content");
          String id = (String) resultDoc.getFieldValue("id"); //id is the uniqueKey field
    
          if (queryResponse.getHighlighting().get(id) != null) {
            List<String> highlightSnippets = queryResponse.getHighlighting().get(id).get("content");
          }
        }

    负载均衡查询

      当你有多个Solr的服务器可以处理查询时,虽然你肯定喜欢选择使用的外部负载平衡器,但是solrj提供了一个简单的内置的轮询负载均衡功能LBHttpSolrServer.

    使用SolrCloud

      SolrJ包含了SolrCloud的一个敏捷的客户端,也就是ZooKeeper.这就意味着你的java应用程序只需要知道Zookeeper实例,并不知道你的solr实例在什么地方,因为这些可以从ZooKeeper中获取.

      为了和SolrCloud交互,需要使用CloudSolrServer的实例,并且传入你得ZooKeeper主机地址(一个或者多个).除了CloudSolrServer的实例化不一样外,其他的处理方式都是一样的:

      

    import org.apache.solr.client.solrj.impl.CloudSolrServer;
    import org.apache.solr.common.SolrInputDocument;
    
    CloudSolrServer server = new CloudSolrServer("localhost:9983");
    server.setDefaultCollection("collection1");
    SolrInputDocument doc = new SolrInputDocument();
    doc.addField( "id", "1234");
    doc.addField( "name", "A lovely summer holiday");
    server.add(doc);
    server.commit();

     

    翻译:http://wiki.apache.org/solr/Solrj,

  • 相关阅读:
    bzoj4289
    bzoj3033
    bzoj3144
    896C
    bzoj4430
    bzoj4455
    bzoj5117
    BZOJ 1564: [NOI2009]二叉查找树
    BZOJ1261: [SCOI2006]zh_tree
    BZOJ1090: [SCOI2003]字符串折叠
  • 原文地址:https://www.cnblogs.com/a198720/p/4274413.html
Copyright © 2011-2022 走看看