solr分页查询和高亮

二、Solr理论

1、 solr基础

因为 Solr 包装并扩展了 Lucene,所以它们使用很多相同的术语。更重要的是,Solr 创建的索引与 Lucene 搜索引擎库完全兼容。通过对 Solr 进行适当的配置,某些情况下可能需要进行编码,Solr 可以阅读和使用构建到其他 Lucene 应用程序中的索引。

在 Solr 和 Lucene 中,使用一个或多个 Document 来构建索引。Document 包括一个或多个 Field。Field 包括名称、内容以及告诉 Solr 如何处理内容的元数据。例如,Field 可以包含字符串、数字、布尔值或者日期,也可以包含你想添加的任何类型,只需用在solr的配置文件中进行相应的配置即可。Field 可以使用大量的选项来描述,这些选项告诉 Solr 在索引和搜索期间如何处理内容。现在,查看一下表 1 中列出的重要属性的子集:

属性名称

描述

Indexed

Indexed Field 可以进行搜索和排序。你还可以在 indexed Field 上运行 Solr 分析过程,此过程可修改内容以改进或更改结果。

Stored

stored Field 内容保存在索引中。这对于检索和醒目显示内容很有用,但对于实际搜索则不是必需的。例如,很多应用程序存储指向内容位置的指针而不是存储实际的文件内容。

2、 solr索引操作

在 Solr 中,通过向部署在 servlet 容器中的 Solr Web 应用程序发送 HTTP 请求来启动索引和搜索。Solr 接受请求,确定要使用的适当 SolrRequestHandler,然后处理请求。通过 HTTP 以同样的方式返回响应。默认配置返回 Solr 的标准 XML 响应。你也可以配置 Solr 的备用响应格式,如json、csv格式的文本。

索引就是接受输入元数据(数据格式在schema.xml中进行配置)并将它们传递给 Solr,从而在 HTTP Post XML 消息中进行索引的过程。你可以向 Solr 索引 servlet 传递四个不同的索引请求:

add/update 允许您向 Solr 添加文档或更新文档。直到提交后才能搜索到这些添加和更新。

commit 告诉 Solr,应该使上次提交以来所做的所有更改都可以搜索到。

optimize 重构 Lucene 的文件以改进搜索性能。索引完成后执行一下优化通常比较好。如果更新比较频繁,则应该在使用率较低的时候安排优化。一个索引无需优化也可以正常地运行。优化是一个耗时较多的过程。

delete 可以通过 id 或查询来指定。按 id 删除将删除具有指定 id 的文档;按查询删除将删除查询返回的所有文档。

Lucene中操作索引也有这几个步骤,但是没有更新。Lucene更新是先删除,然后添加索引。因为更新索引在一定情况下,效率没有先删除后添加的效率好。

3、 搜索

添加文档后,就可以搜索这些文档了。Solr 接受 HTTP GET 和 HTTP POST 查询消息。收到的查询由相应的 SolrRequestHandler 进行处理。

solr查询参数描述:

参数

描述

示例

q

Solr 中用来搜索的查询。有关该语法的完整描述,请参阅 参考资料。可以通过追加一个分号和已索引且未进行断词的字段(下面会进行解释)的名称来包含排序信息。默认的排序是 score desc,指按记分降序排序。

q=myField:Java AND otherField:developerWorks; date asc此查询搜索指定的两个字段,并根据一个日期字段对结果进行排序。

start

将初始偏移量指定到结果集中。可用于对结果进行分页。默认值为 0。

start=15 返回从第 15 个结果开始的结果。

rows

返回文档的最大数目。默认值为 10。

rows=25,返回25个结果集

fq

提供一个可选的筛选器查询。查询结果被限制为仅搜索筛选器查询返回的结果。筛选过的查询由 Solr 进行缓存。它们对提高复杂查询的速度非常有用。

任何可以用 q 参数传递的有效查询,排序信息除外。

hl

当 hl=true 时,在查询响应中醒目显示片段。默认为 false。参看醒目显示参数(见 参考资料)。

hl=true

fl

作为逗号分隔的列表指定文档结果中应返回的 Field 集。默认为 “*”,指所有的字段。“score” 指还应返回记分。

*,score

sort

排序,对查询结果进行排序,参考

sort=date asc,price desc

4、 solr模式

上面有提到schema.xml这个配置,这个配置可以在你下载solr包的安装解压目录的apache-solr-3.4.0\example\solr\conf中找到,它就是solr模式关联的文件。打开这个配置文件,你会发现有详细的注释。

模式组织主要分为三个重要配置

types 部分是一些常见的可重用定义,定义了 Solr(和 Lucene)如何处理 Field。也就是添加到索引中的xml文件属性中的类型,如int、text、date等

fileds是你添加到索引文件中出现的属性名称,而声明类型就需要用到上面的types

其他配置有

uniqueKey 唯一键,这里配置的是上面出现的fileds,一般是id、url等不重复的。在更新、删除的时候可以用到。

defaultSearchField默认搜索属性,如q=solr就是默认的搜索那个字段

solrQueryParser查询转换模式,是并且还是或者(and/or)

5、 索引配置

Solr 性能因素,来了解与各种更改相关的性能权衡。

表 1 概括了可控制 Solr 索引处理的各种因素:

因素

描述

useCompoundFile

通过将很多 Lucene 内部文件整合到单一一个文件来减少使用中的文件的数量。这可有助于减少 Solr 使用的文件句柄数目,代价是降低了性能。除非是应用程序用完了文件句柄,否则 false 的默认值应该就已经足够。

mergeFactor

决定低水平的 Lucene 段被合并的频率。较小的值(最小为 2)使用的内存较少但导致的索引时间也更慢。较大的值可使索引时间变快但会牺牲较多的内存。

maxBufferedDocs

在合并内存中文档和创建新段之前,定义所需索引的最小文档数。段 是用来存储索引信息的 Lucene 文件。较大的值可使索引时间变快但会牺牲较多的内存。

maxMergeDocs

控制可由 Solr 合并的 Document 的最大数。较小的值 (< 10,000) 最适合于具有大量更新的应用程序。

maxFieldLength

对于给定的 Document,控制可添加到 Field 的最大条目数,进而截断该文档。如果文档可能会很大,就需要增加这个数值。然而,若将这个值设置得过高会导致内存不足错误。

unlockOnStartup

unlockOnStartup 告知 Solr 忽略在多线程环境中用来保护索引的锁定机制。在某些情况下,索引可能会由于不正确的关机或其他错误而一直处于锁定,这就妨碍了添加和更新。将其设置为 true 可以禁用启动锁定,进而允许进行添加和更新。

6、 查询处理配置

<maxBooleanClauses> 标记定义了可组合在一起形成一个查询的子句数量的上限。对于大多数应用程序而言,默认的 1024 就应该已经足够;然而,如果应用程序大量使用了通配符或范围查询,增加这个限值将能避免当值超出时,抛出 TooManyClausesException。

若应用程序预期只会检索 Document 上少数几个 Field,那么可以将 <enableLazyFieldLoading> 属性设置为 true。懒散加载的一个常见场景大都发生在应用程序返回和显示一系列搜索结果的时候,用户常常会单击其中的一个来查看存储在此索引中的原始文档。初始的显示常常只需要显示很短的一段信息。若考虑到检索大型 Document 的代价,除非必需,否则就应该避免加载整个文档。

<query> 部分负责定义与在 Solr 中发生的事件相关的几个选项。Searcher 的 Java 类来处理 Query 实例。要改进这一设计和显著提高性能,把这些新的 Searcher 联机以便为现场用户提供查询服务之前,先对它们进行 “热身”。<query> 部分中的 <listener> 选项定义 newSearcher 和 firstSearcher 事件,您可以使用这些事件来指定实例化新搜索程序或第一个搜索程序时应该执行哪些查询。如果应用程序期望请求某些特定的查询,那么在创建新搜索程序或第一个搜索程序时就应该反注释这些部分并执行适当的查询。

solrconfig.xml 文件的剩余部分,除 <admin> 之外,涵盖了与 缓存、复制 和 扩展或定制 Solr 有关的项目。admin 部分让您可以定制管理界面。有关配置 admin 节的更多信息,请参看solrconfig.xml 文件中的注释。

7、 监视、记录和统计数据

用于监视、记录和统计数据的 Solr 管理选项

菜单名

URL

描述

Statistics

http://localhost:8080/solr/admin/stats.jsp

Statistics 管理页提供了与 Solr 性能相关的很多有用的统计数据。这些数据包括:

关于何时加载索引以及索引中有多少文档的信息。

关于用来服务查询的 SolrRequestHandler 的有用信息。

涵盖索引过程的数据,包括添加、删除、提交等的数量。

缓存实现和 hit/miss/eviction 信息

Info

http://localhost:8080/solr/admin/registry.jsp

有关正在运行的 Solr 的版本以及在当前实现中进行查询、更新和缓存所使用的类的详细信息。此外,还包括文件存于 Solr subversion 存储库的何处的信息以及对该文件功能的一个简要描述。

Distribution

http://localhost:8080/solr/admin/distributiondump.jsp

显示与索引发布和复制有关的信息。更多信息,请参见 “发布和复制” 一节。

Ping

http://localhost:8080/solr/admin/ping

向服务器发出 ping 请求,包括在 solrconfig.xml 文件的 admin 部分定义的请求。

Logging

http://localhost:8080/solr/admin/logging.jsp

让您可以动态更改当前应用程序的日志记录等级。更改日志记录等级对于调试在执行过程中可能出现的问题非常有用。

properties

http: //localhost:8080/solr/admin/get-properties.jsp

显示当前系统正在使用的所有 Java 系统属性。Solr 支持通过命令行的系统属性替换。有关实现此特性的更多信息,请参见 solrconfig.xml 文件。

Thread dump

http://localhost:8080/solr/admin/threaddump.jsp

thread dump 选项显示了在 JVM 中运行的所有线程的堆栈跟踪信息。

8、 智能缓存

智能缓存是让 Solr 得以成为引人瞩目的搜索服务器的一个关键性能特征。Solr 提供了四种不同的缓存类型,所有四种类型都可在 solrconfig.xml 的 <query> 部分中配置。solrconfig.xml 文件中所用的标记名列出了这些缓存类型:

缓存标记名

描述

能否自热

filterCache

通过存储一个匹配给定查询的文档 id 的无序集,过滤器让 Solr 能够有效提高查询的性能。缓存这些过滤器意味着对 Solr 的重复调用可以导致结果集的快速查找。更常见的场景是缓存一个过滤器,然后再发起后续的精炼查询,这种查询能使用过滤器来限制要搜索的文档数。

可以

queryResultCache

为查询、排序条件和所请求文档的数量缓存文档 id 的有序 集合。

可以

documentCache

缓存 Lucene Document,使用内部 Lucene 文档 id(以便不与 Solr 惟一 id 相混淆)。由于 Lucene 的内部 Document id 可以因索引操作而更改,这种缓存不能自热。

不可以

Named caches

命名缓存是用户定义的缓存,可被 Solr 定制插件 所使用。

可以,如果实现了 org.apache.solr.search.CacheRegenerator 的话。

每个缓存声明都接受最多四个属性:

class 是缓存实现的 Java 名。

size 是最大的条目数。

initialSize 是缓存的初始大小。

autoWarmCount 是取自旧缓存以预热新缓存的条目数。如果条目很多,就意味着缓存的hit 会更多,只不过需要花更长的预热时间。

三、实例

  1、获取SolrServer 用单例的形式写了个类;

package com.stu.commons; 
import java.net.MalformedURLException;
import org.apache.solr.client.solrj.impl.CommonsHttpSolrServer;

/**
 * Description:
 * @author  LiChunming
 * @version V1.0 
 * @createDateTime:2012-2-27 下午03:49:04 
 * @Company: MSD. 
 * @Copyright: Copyright (c) 2011
 **/
public class SolrServer {
    private static SolrServer solrServer = null;
    private static CommonsHttpSolrServer server=null;
    private static String url="http://localhost:8080/solr";
    
    public static synchronized SolrServer getInstance() {
        if (solrServer==null){
           solrServer=new SolrServer();
        }
        return solrServer;
    }
    public static CommonsHttpSolrServer getServer(){
         try {
            if(server==null){
              server = new CommonsHttpSolrServer(url);
              server.setSoTimeout(1000);  // socket read timeout
              server.setConnectionTimeout(1000);
              server.setDefaultMaxConnectionsPerHost(100);
              server.setMaxTotalConnections(100);
              server.setFollowRedirects(false);  // defaults to false
              //allowCompression defaults to false.
              //Server side must support gzip or deflate for this to have any effect.
              server.setAllowCompression(true);
              server.setMaxRetries(1); // defaults to 0.  > 1 not recommended.
            }
        } catch (MalformedURLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return server;
    }
}
2、打开目录tomcat-7.0.14\solr\conf\schema.xml文件在<fields>下增加下字段。用于增加到搜索引擎的字段

<span style="white-space:pre">	</span><field name="blogId" type="string" indexed="true" stored="true"  required="true"/>
<span style="white-space:pre">	</span><field name="content" type="text" indexed="true" stored="true" omitNorms="true" />
<span style="white-space:pre">	</span><field name="bTypeId" type="string" indexed="true" stored="true" />
<span style="white-space:pre">	</span><field name="bTypeName" type="string" indexed="true" stored="true" />
<span style="white-space:pre">	</span><field name="nickName" type="string" indexed="true" stored="true" />
<span style="white-space:pre">	</span><field name="createTime" type="date" indexed="true" stored="true" omitNorms="true" />
3、增加信息到引擎文件中

<span style="white-space:pre">	</span>public void writerBlog(BlogsDO blog) {
         // TODO Auto-generated method stub
          try {
              blog.setId(SerialNumberUtil.getRandomNum(4));
               //获取连接服务
               CommonsHttpSolrServer solrServer= SolrServer.getInstance().getServer();
               SolrInputDocument doc1 = new SolrInputDocument();
               doc1.addField("id", SerialNumberUtil.getRandomNum(4) );
               doc1.addField("blogId", blog.getBlogsId());
               doc1.addField("title",blog.getTitle()  );
               doc1.addField("bTypeId", blog.getbTypeId());
               doc1.addField("bTypeName", blog.getbTypeName());
               doc1.addField("content",  blog.getContent());
               String createTime=DateUtils.formatDate(blog.getGmtCreate(),  "yyyyMMddHHmmss");
               doc1.addField("createTime",createTime);
               doc1.addField("nickName",blog.getNickName());
               solrServer.add(doc1);
               solrServer.commit();
         } catch (SolrServerException e) {
             // TODO Auto-generated catch block
             e.printStackTrace();
         } catch (IOException e) {
             // TODO Auto-generated catch block
             e.printStackTrace();
         }
     }
实体类 BlogsDO

package com.stu.entity; 
 
 import java.io.Serializable;
 import java.util.Date;
 import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.GeneratedValue;
 import javax.persistence.GenerationType;
 import javax.persistence.Id;
 import javax.persistence.Table;
 import javax.persistence.Transient;
 import org.apache.solr.client.solrj.beans.Field;
 
 import com.stu.commons.util.DateUtils;
 
 /**
  * Description:
  * @author  LiChunming
  * @version V1.0 
  * @createDateTime:2011-5-17 下午04:38:11 
  * @Company: MSD. 
  * @Copyright: Copyright (c) 2011
  **/
 @Entity
 @Table(name="blogs")
 public class BlogsDO implements Serializable{
     /**
      * 
 */
     private static final long serialVersionUID = -4721368786493126226L;
     @Field
     private String id;
     @Field("blogId")
     private Integer blogsId;
     @Field
     private String title;
     @Field
     private String content="";
     @Field("createTime")
     private Date gmtCreate;
     @Field
     private String nickName;
     @Field
     private String bTypeId;
     @Field
     private String bTypeName;
     private Date gmtModified;
     private String revDate;
     private String sDate="";
     private String eDate="";
     
     @Transient
     public String getId() {
         return id;
     }
     public void setId(String id) {
         this.id = id;
     }
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     public Integer getBlogsId() {
         return blogsId;
     }
     public void setBlogsId(Integer blogsId) {
         this.blogsId = blogsId;
     }
     public String getTitle() {
         return title;
     }
     public void setTitle(String title) {
         this.title = title;
     }
     public String getContent() {
         return content;
     }
     public void setContent(String content) {
         this.content = content;
     }
     
     public String getNickName() {
         return nickName;
     }
     public void setNickName(String nickName) {
         this.nickName = nickName;
     }
     
     public String getbTypeId() {
         return bTypeId;
     }
     public void setbTypeId(String bTypeId) {
         this.bTypeId = bTypeId;
     }
     @Column(name="gmt_create")
     public Date getGmtCreate() {
         return gmtCreate;
     }
     public void setGmtCreate(Date gmtCreate) {
         this.gmtCreate = gmtCreate;
     }
     @Column(name="gmt_modified")
     public Date getGmtModified() {
         return gmtModified;
     }
     public void setGmtModified(Date gmtModified) {
         this.gmtModified = gmtModified;
     }
     @Transient
     public String getRevDate() {
          if (this.gmtCreate == null) {
                 return null;
             }
           return DateUtils.formatDate(gmtCreate, "yyyy-MM-dd HH:mm:ss");
     }
     public void setRevDate(String revDate) {
         this.revDate = revDate;
     }
     @Transient
     public String getbTypeName() {
         return bTypeName;
     }
     public void setbTypeName(String bTypeName) {
         this.bTypeName = bTypeName;
     }
     @Transient
     public String getsDate() {
         return sDate;
     }
     public void setsDate(String sDate) {
         this.sDate = sDate;
     }
     @Transient
     public String geteDate() {
         return eDate;
     }
     public void seteDate(String eDate) {
         this.eDate = eDate;
     }
     @Override
     public String toString() {
         return this.id + "#" + this.blogsId + "#" + this.title + "#" + this.content + "#" + this.bTypeId + "#" + this.bTypeName + "#" + this.nickName+"#" + this.gmtCreate;
     } 
 }
5、 文档查询

public List<BlogsDO> searchBlogsList(String content, String bTypeId,
             String sDate, String eDate, Page page) throws IOException,
             ParseException {
          List<BlogsDO> blogList=new ArrayList<BlogsDO>();
          BlogsDO blogsDO=null;
          CommonsHttpSolrServer solrServer= SolrServer.getInstance().getServer();
          SolrQuery sQuery = new SolrQuery();
          String para="";
         //OR 或者  OR 一定要大写
          if(StringUtils.isNotEmpty(content)){
              para=para+"(title:"+content+" OR content:"+content+")";
              //空格 等同于 OR
 // para=para+"(title:"+content+"  content:"+content+")";
          }
         //AND 并且  AND一定要大写
          if(!bTypeId.equals("-1")){
              if(StringUtils.isNotEmpty(para)){
                   para=para+" AND bTypeId:"+bTypeId;
              }else{
                   para=para+"  bTypeId:"+bTypeId;
              }
          }
          if(StringUtils.isNotEmpty(sDate) && StringUtils.isNotEmpty(eDate)){
              if(StringUtils.isNotEmpty(para)){
                  para=para+" AND createTime:["+sDate+" TO "+eDate+"]";
              }else{
                  para=para+" createTime:["+sDate+" TO "+eDate+"]";
              }
         }
         //查询name包含solr apple
 //sQuery.setQuery("name:solr,apple");
 //manu不包含inc
 //sQuery.setQuery("name:solr,apple NOT manu:inc");
 //50 <= price <= 200
 //sQuery.setQuery("price:[50 TO 200]");
 //sQuery.setQuery("popularity:[5 TO 6]");
 //params.setQuery("price:[50 TO 200] - popularity:[5 TO 6]");
 //params.setQuery("price:[50 TO 200] + popularity:[5 TO 6]");
 //50 <= price <= 200 AND 5 <= popularity <= 6
 //sQuery.setQuery("price:[50 TO 200] AND popularity:[5 TO 6]");
 //sQuery.setQuery("price:[50 TO 200] OR popularity:[5 TO 6]");
         
 // 查询关键词,*:*代表所有属性、所有值,即所有index
         if(!StringUtils.isNotEmpty(para)){
              para="*:*"; 
          }
          logger.info("para:"+para);
          sQuery.setQuery(para);
          //设置分页  start=0就是从0开始,,rows=5当前返回5条记录,第二页就是变化start这个值为5就可以了。
          sQuery.setStart((page.getCurrentPage()-1)*page.getPerPageSize());
          sQuery.setRows(page.getPerPageSize());
          //排序 如果按照blogId 排序,,那么将blogId desc(or asc) 改成 id desc(or asc)
          sQuery.addSortField("blogId", ORDER.asc);
         
          //设置高亮
         sQuery.setHighlight(true); // 开启高亮组件
         sQuery.addHighlightField("content");// 高亮字段
         sQuery.addHighlightField("title");// 高亮字段
         sQuery.setHighlightSimplePre("<font color='red'>");//标记,高亮关键字前缀
         sQuery.setHighlightSimplePost("</font>");//后缀
         sQuery.setHighlightSnippets(2);//结果分片数,默认为1
         sQuery.setHighlightFragsize(1000);//每个分片的最大长度,默认为100
         
 //分片信息
         sQuery.setFacet(true)
             .setFacetMinCount(1)
             .setFacetLimit(5)//段
             .addFacetField("content");//分片字段
         
         try {
             QueryResponse response = solrServer.query(sQuery);
             SolrDocumentList list = response.getResults();
             Integer counts=(int) list.getNumFound();
             logger.info("counts:"+counts);
             page.setCounts(counts);
             //获取所有高亮的字段
             Map<String,Map<String,List<String>>> highlightMap=response.getHighlighting();
             String blogId="";
             for (SolrDocument solrDocument : list) {
                 blogsDO=new BlogsDO();
                 blogId=solrDocument.getFieldValue("blogId").toString();
                 blogsDO.setBlogsId(Integer.valueOf(blogId));
                 blogsDO.setbTypeId(solrDocument.getFieldValue("bTypeId").toString());
                 blogsDO.setbTypeName(solrDocument.getFieldValue("bTypeName").toString());
                 blogsDO.setNickName(solrDocument.getFieldValue("nickName").toString());
                 List<String> titleList=highlightMap.get(blogId).get("title");
                 List<String> contentList=highlightMap.get(blogId).get("content");
                 if(titleList!=null && titleList.size()>0){
                     blogsDO.setTitle(titleList.get(0));
                 }else{
                     //获取并设置高亮的字段title
                     blogsDO.setTitle(solrDocument.getFieldValue("title").toString());
                 }
                 if(contentList!=null && contentList.size()>0){
                     blogsDO.setContent(contentList.get(0));
                 }else{
                     //获取并设置高亮的字段content
                     blogsDO.setContent(solrDocument.getFieldValue("content").toString());
                 }
                 blogsDO.setRevDate(solrDocument.getFieldValue("createTime").toString());
                 SimpleDateFormat sdf =  new  SimpleDateFormat("yyyyMMddHHmmss"); 
                 try {
                     blogsDO.setGmtCreate(sdf.parse(solrDocument.getFieldValue("createTime").toString()));
                 } catch (java.text.ParseException e) {
                     // TODO Auto-generated catch block
                     e.printStackTrace();
                 }
                 blogList.add(blogsDO);
             }
         } catch (SolrServerException e) {
             // TODO Auto-generated catch block
             e.printStackTrace();
         }
         return blogList;
     }
注: DocumentObjectBinder对象将SolrInputDocument 和 BlogsDO对象相互转换

            //获取所有高亮的字段
            Map<String,Map<String,List<String>>> highlightMap=response.getHighlighting();
    		for (SolrDocument  sd : list) {
    			
    			if(null!=highlightMap.get(sd.getFieldValue("nid").toString()).get("title")){
        			sd.setField("title",highlightMap.get(sd.getFieldValue("nid").toString()).get("title").toString());      			
            	}
    			if(null!=highlightMap.get(sd.getFieldValue("nid").toString()).get("content")){
    				sd.setField("content", highlightMap.get(sd.getFieldValue("nid").toString()).get("content").toString()); 
    			}
  
            } 
    	    DocumentObjectBinder binder = new DocumentObjectBinder();   		
            List<CompanyNews> nlist = binder.getBeans(CompanyNews.class, list);//<span style="font-family: Georgia, 'Times New Roman', Times, san-serif;">SolrDocumentList转换成对象list</span>

附件:自己文件

@Service
public class SolrService {

    private static Logger logger = Logger.getLogger(SolrService.class);
    public static int JobsId = 219443;// start jobsid  
    public SolrServer solrServer = null;// new  
                                        // HttpSolrServer("http://192.168.2.100:8080/solr/JobsOtherWeb1");  
    
    // 1、 创建solrserver对象:  
    public SolrServer createSolrServer() {  
        HttpSolrServer solr = null;  
        try {  
            solr = new HttpSolrServer(  
                    "http://localhost:8983/solr");  
            solr.setConnectionTimeout(100);  
            solr.setDefaultMaxConnectionsPerHost(100);  
            solr.setMaxTotalConnections(100);  
        } catch (Exception e) {  
            System.out.println("请检查服务器或端口是否开启!");  
            e.printStackTrace();  
        }  
        return solr;  
    }   
    // 简单的查询,取出二十个  
    public  Map<String,Object> querySolrDocumentList(String key,int time,String indCode,String wandCode,int start,int size){
    	
    	solrServer = createSolrServer(); 
    	SolrQuery query = new SolrQuery(); 	
    	SolrDocumentList list = new SolrDocumentList();
    	Map<String,Object> map = new HashMap<String, Object>();
        Date now = new Date();
        String dtStart = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(now);  
        System.out.println("开始时间:" + dtStart + "\n"); 
    	String para="";
    	
       	if(StringUtils.isNotEmpty(indCode)){
    		query.setFilterQueries("citicsIndCode:"+indCode+"*");
    	}
        if(StringUtils.isNotEmpty(key)){
            //para=para+"(title:"+key+" OR keyword:"+key+" OR content:"+key+")";
         	para=para+"(keywords:"+key+")";
             //空格 等同于 OR
         }
         
         if(StringUtils.isNotEmpty(wandCode)){
             //para=para+"(title:"+key+" OR keyword:"+key+" OR content:"+key+")";
          	para=para+"(windCode:"+wandCode+")";
              //空格 等同于 OR
          }
        if(time>0){
        	//query.setFacet(true);// 设置facet=on 
            //query.addFacetField(new String[] {"timeStamp"});// 设置需要facet的字段  
            SimpleDateFormat time0 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
            SimpleDateFormat time1 = new SimpleDateFormat("yyyy-MM-dd");  
            SimpleDateFormat time2 = new SimpleDateFormat("HH:mm:ss");  
            // date.getYear()+"-"+date.getMonth()+"-"+date.getDay()+"T"+date.getHours()+":"+date.getMinutes()+":"+date.getSeconds();           
            Calendar c = Calendar.getInstance();  
            try {
				c.setTime(time0.parse(time1.format(c.getTime()) + " 23:59:59"));
	            Date date = c.getTime();  
	            String dateNow = time1.format(date) + "T" + time2.format(date) + "Z";  
	            c.setTime(time0.parse(time1.format(c.getTime()) + " 23:59:59"));  
	            date = c.getTime();  
	            // 当天  
	            if(time==1)
	            	c.add(Calendar.DATE, -1);             
	            if(time==3)
	            	c.add(Calendar.DATE, -2);
	            if(time==7)
	            	c.add(Calendar.DATE, -7);
	            if(time==20)
	            	c.add(Calendar.DATE, -51);
	            date = c.getTime(); 

	            para=para+"(timeStamp:["+time1.format(date) + "T"  
	                         + time2.format(date) + "Z" + " TO " + dateNow + "])";
	            logger.info("开始时间"+time1.format(date) + "T"  
	                        + time2.format(date) + "Z" + " TO " + dateNow);
			} catch (ParseException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}  
        }
        if(!StringUtils.isNotEmpty(para)){
            para="*:*"; 
        }
        logger.info("-----------query="+query);
        query.setQuery(para);
        query.setStart(start);
        query.setRows(size);  
        //query.addSort("timeStamp", ORDER.desc);
        
        //设置高亮
        query.setHighlight(true); // 开启高亮组件
        query.set("hl.highlightMultiTerm","true");//启用多字段高亮
        query.addHighlightField("content");// 高亮字段
        query.addHighlightField("title");// 高亮字段
        query.setHighlightSimplePre("<font color='red'>");//标记,高亮关键字前缀
        query.setHighlightSimplePost("</font>");//后缀
        query.setHighlightSnippets(2);//结果分片数,默认为1
        query.setHighlightFragsize(1000);//每个分片的最大长度,默认为100
    	query.setQuery(para);

		try {
	        QueryResponse  response = solrServer.query(query);	        
	        list = response.getResults();
	        System.out.println("++++++++++++++" +list.toString());
            Integer counts=(int) list.getNumFound();
            logger.info("counts:"+counts);
            //page.setCounts(counts);
            //获取所有高亮的字段
            Map<String,Map<String,List<String>>> highlightMap=response.getHighlighting();
    		for (SolrDocument  sd : list) {
    			
    			if(null!=highlightMap.get(sd.getFieldValue("nid").toString()).get("title")){
        			sd.setField("title",highlightMap.get(sd.getFieldValue("nid").toString()).get("title").toString());      			
            	}
    			if(null!=highlightMap.get(sd.getFieldValue("nid").toString()).get("content")){
    				sd.setField("content", highlightMap.get(sd.getFieldValue("nid").toString()).get("content").toString()); 
    			}
  
            } 
    		DocumentObjectBinder binder = new DocumentObjectBinder();   		
            List<CompanyNews> nlist = binder.getBeans(CompanyNews.class, list);

    		System.out.println("++++++++++++++" +nlist.toString());
    		map.put("count", counts);
    		map.put("data", nlist);
            solrServer.shutdown();   
		} catch (SolrServerException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

    	return map;
    }



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 如果你想在Solr中执行分组查询,并且你的字段包含多个值,你可以使用Solr的多值分组功能。为了使用这个功能,你需要使用Solr的分组查询语法,并在查询中指定“group.field”参数来指定要分组的字段。然后,您可以使用Solr的“group.limit”参数来指定每个分组中包含的文档数的最大值。这将确保您的分组查询结果仅包含与每个分组相关的最相关文档。从Solr 4.0开始,您还可以使用Solr的“group.format”参数来指定分组查询结果的格式,以便更好地满足您的需求。 ### 回答2: Solr是一个强大的搜索引擎,可以用于进行高效的分组查询。当我们需要对包含多个值的字段进行分组查询时,可以通过使用Solr的facet功能来实现。 在Solr中,可以使用facet.field参数指定要进行分组的多值字段。例如,如果我们有一个字段名为"tags",该字段包含多个标签,可以通过将facet.field设置为"tags"来进行分组查询。在搜索请求中,我们需要设置facet参数为true来启用分组查询。 当我们执行搜索请求时,Solr会计算每个标签的出现次数,并返回每个标签及其对应的文档数。这样,我们可以获得每个标签的分组统计信息。 我们还可以通过设置facet.limit参数来限制返回的分组结果数量。如果我们想要获取前n个最常见的标签,可以将facet.limit设置为n。 另外,我们还可以对分组结果进行排序,以便按照某个特定的标准对标签进行排序。例如,我们可以使用facet.sort参数将分组结果按照文档数目或者标签名称进行排序。 除了对整个多值字段进行分组查询,我们还可以在分组查询中指定条件。例如,我们可以使用facet.query参数来指定额外的条件,并对满足条件的文档进行分组查询。 总结来说,Solr可以通过使用facet功能对包含多个值的字段进行分组查询。我们可以指定要进行分组的字段,并可以设置额外的条件、排序和限制来获取所需的分组统计信息。 ### 回答3: Solr是一个开源的搜索平台,它支持多值字段的分组查询。在Solr中,可以使用facet查询来实现分组查询,并且可以应用于包含多值的字段。 要对包含多值的字段进行分组查询,首先需要在solrconfig.xml文件中配置相应的字段类型。可以使用Solr提供的一些已有的多值字段类型,例如"string_mv"、"text_general_mv"等,也可以根据需要自定义字段类型。 在查询时,可以使用facet.field参数指定需要进行分组查询的字段名。当指定的字段是一个多值字段时,Solr会根据每个值进行分组。结果中将包含该字段的每个值作为分组的key,并统计每个分组出现的次数。 例如,假设有一个包含多个标签的字段"tags",现在需要对"tags"字段进行分组查询。可以使用如下查询语句: ``` /select?q=*:*&facet=true&facet.field=tags ``` 执行该查询后,Solr将返回一个结果集,其中包含了"tags"字段的每个值作为分组的key,并统计了每个分组出现的次数。这样就实现了对包含多值的字段进行分组查询。 需要注意的是,对于大量数据或者需要更复杂的聚合操作的情况,可能需要使用更高级的分组查询功能,例如利用facet.pivot参数进行多级分组或者使用facet.query参数进行条件过滤等。 综上所述,Solr支持对包含多值的字段进行分组查询,通过配置字段类型和使用facet查询参数,可以轻松实现这一功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值