Solr开发文档(转)

出处:http://www.cnblogs.com/hoojo/archive/2011/10/21/2220431.htmlhtml

Solr 是一种可供企业使用的、基于 Lucene 的搜索服务器,它支持层面搜索、命中醒目显示和多种输出格式。在这篇文章中,将介绍 Solr 并展现如何轻松地将其表现优异的全文本搜索功能加入到 Web 应用程序中。java

开发环境:web

System:Windows算法

WebBrowser:IE6+、Firefox3+apache

JDK:1.6+json

JavaEE Server:tomcat5.0.2.八、tomcat6api

IDE:eclipse、MyEclipse 8缓存

 

开发依赖库:tomcat

JavaEE 五、solr 3.4ruby

 

我的博客:

http://hoojo.cnblogs.com

http://blog.csdn.net/IBM_hoojo

email: hoojo_@126.com

 

1、配置和安装solr

一、 首先去apache官方网站下载solr,下载地址

http://labs.renren.com/apache-mirror//lucene/solr/3.4.0/

目前最新的是3.4的版本

 

二、 下载后解压目录以下

clip_image002

client是一个ruby实现的示例,这个咱们暂时无论

contrib有一些功能模块是须要的jar包

dist是打包发布好的工程war包

docs是帮助文档

example是示例,里面有打包部署好的solr工程示例和servlet容器jetty。若是你没有tomcat能够直接使用Jetty服务器部署你的solr示例。

 

三、 发布、部署solr示例

A、 利用自带的Jetty服务器

首先在dos命令中进入到下载好的solr解压的目录apache-solr-3.4.0的example目录

cd E:\JAR\solr\apache-solr-3.4.0\example

而后利用java命令,启动jetty服务器。Java –jar start.jar

clip_image004

启动Jetty成功后,若是没有看到错误消息,你能够看到端口信息。

clip_image006

若是你的端口冲突了,你能够到解压的solr示例包的example/etc的jetty.xml中,修改端口port信息。

<Set name="port">

<SystemProperty name="jetty.port" default="8983"/>

</Set>

 

B、 利用tomcat发布solr示例

将下载的solr解压后,进入apache-solr-3.4.0\dist目录,将里面的solr.war放到D:\tomcat-6.0.28\webapps目录下,启动tomcat会自动解压。(固然,你也能够手动解压放到wabapps目录下)

固然你也能够设置context指向你的solr工程,在D:\tomcat-6.0.28\conf\Catalina\localhost目录加入solr.xml配置,配置以下:

<Context docBase="D:\solr.war" debug="0" crossContext="true" >
    <Environment name="solr/home" type="java.lang.String" value="D:\solr" override="true" />
</Context>

上面的2步都是同样的,这样尚未完。启动后你可能会看到以下错误:

clip_image008

咱们须要将一些配置和index库文件也放到解压好的solr工程下。咱们到解压的apache-solr-3.4.0\example\solr目录下,将里面的conf和data目录copy到刚才咱们部署的D:\tomcat-6.0.28\webapps\solr工程目录下。或是copy到你的solr.xml中的context指定的路径下工程目录中。

重启tomcat就ok了。

 

四、 这个时候你就能够访问http://localhost:8983/solr/admin/你就能够看到以下界面:

clip_image010

在Query String中输入solr,点击Search就能够查询到相应的结果,结果以xml形式返回。固然你也能够设置返回数据类型为json。

<?xml version="1.0" encoding="UTF-8"?>
<response>
<lst name="responseHeader">
  <int name="status">0</int>
  <int name="QTime">0</int>
  <lst name="params">
    <str name="indent">on</str>
    <str name="start">0</str>
    <str name="q">solr</str>
    <str name="version">2.2</str>
    <str name="rows">10</str>
  </lst>
</lst>
<result name="response" numFound="1" start="0">
  <doc>
    <arr name="cat"><str>software</str><str>search</str></arr>
    <arr name="features"><str>Advanced Full-Text Search Capabilities using Lucene</str><str>Optimized for High Volume Web Traffic</str><str>Standards Based Open Interfaces - XML and HTTP</str>
      <str>Comprehensive HTML Administration Interfaces</str><str>Scalability - Efficient Replication to other Solr Search Servers</str><str>Flexible and Adaptable with XML configuration and Schema</str><str>Good unicode support: h¨¦llo (hello with an accent over the e)</str></arr>
    <str name="id">SOLR1000</str>
    <bool name="inStock">true</bool>
    <date name="incubationdate_dt">2006-01-17T00:00:00Z</date>
    <str name="manu">Apache Software Foundation</str>
    <str name="name">Solr, the Enterprise Search Server</str>
    <int name="popularity">10</int>
    <float name="price">0.0</float>
  </doc>
</result>
</response>
 

 

2、Solr理论

一、 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 内容保存在索引中。这对于检索和醒目显示内容颇有用,但对于实际搜索则不是必需的。例如,不少应用程序存储指向内容位置的指针而不是存储实际的文件内容。

 

二、 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更新是先删除,而后添加索引。由于更新索引在必定状况下,效率没有先删除后添加的效率好。

 

三、 搜索

添加文档后,就能够搜索这些文档了。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

 

四、 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)

schema配置类型

<fieldType name="text" class="solr.TextField" positionIncrementGap="100">
    <analyzer type="index">
        <tokenizer class="solr.WhitespaceTokenizerFactory" />
        <filter class="solr.StopFilterFactory" ignoreCase="true"
            words="stopwords.txt" />
        <filter class="solr.WordDelimiterFilterFactory"
            generateWordParts="1" generateNumberParts="1" catenateWords="1"
            catenateNumbers="1" catenateAll="0" />
        <filter class="solr.LowerCaseFilterFactory" />
        <filter class="solr.EnglishPorterFilterFactory" protected="protwords.txt" />
        <filter class="solr.RemoveDuplicatesTokenFilterFactory" />
    </analyzer>
    <analyzer type="query">
        <tokenizer class="solr.WhitespaceTokenizerFactory" />
        <filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt"
            ignoreCase="true" expand="true" />
        <filter class="solr.StopFilterFactory" ignoreCase="true"
            words="stopwords.txt" />
        <filter class="solr.WordDelimiterFilterFactory"
            generateWordParts="1" generateNumberParts="1" catenateWords="0"
            catenateNumbers="0" catenateAll="0" />
        <filter class="solr.LowerCaseFilterFactory" />
        <filter class="solr.EnglishPorterFilterFactory" protected="protwords.txt" />
        <filter class="solr.RemoveDuplicatesTokenFilterFactory" />
    </analyzer>
</fieldType>

上面就是一个type了,而后你在fields配置field的时候就能够用这个type。

 

首先,上面的fieldType的配置中有两个analyzer,它是分词器。主要把咱们的数据进行分割成一个个的词语。词干提取、中止词删除以及类似的操做都被应用于标记,而后才进行索引和搜索,致使使用相同类型的标记。

上面的应用程序的 Solr 的fieldType配置按如下步骤进行设置:

Ø 根据空白进行断词,而后删除全部的公共词(StopFilterFactory)

Ø 使用破折号处理特殊的大小写、大小写转换等等。(WordDelimiterFilterFactory);将全部条目处理为小写(LowerCaseFilterFactory)

Ø 使用 Porter Stemming 算法进行词干提取(EnglishPorterFilterFactory)

Ø 删除全部的副本(RemoveDuplicatesTokenFilterFactory)

Schema属性、字段

<field name="id" type="string" indexed="true" stored="true"
    required="true" />
<field name="sku" type="text_en_splitting_tight" indexed="true"
    stored="true" omitNorms="true" />
<field name="name" type="text_general" indexed="true" stored="true" />
<field name="alphaNameSort" type="alphaOnlySort" indexed="true"
    stored="false" />
<field name="manu" type="text_general" indexed="true" stored="true"
    omitNorms="true" />
<field name="cat" type="string" indexed="true" stored="true"
    multiValued="true" />
<field name="features" type="text_general" indexed="true" stored="true"
    multiValued="true" />
<field name="includes" type="text_general" indexed="true" stored="true"
    termVectors="true" termPositions="true" termOffsets="true" />

属性是在添加索引、查询的时候必须的配置,若是你不加这些配置。是没法完成索引的建立的。

首先id属性是未经分析的字符串类型,是能够索引、存储的,而且是惟一的。

sku是一个通过分词器分析出来的英文切割的类型字符,能够索引、存储、不要存储规范

multiValued 属性是一个特殊的例子,指 Document 能够拥有一个相同名称添加了屡次的 Field。

omitNorms 属性告诉 Solr(和 Lucene)不要存储规范。

介绍一下字段声明下方的 <dynamicField> 声明。动态字段是一些特殊类型的字段,能够在任什么时候候将这些字段添加到任何文档中,由字段声明定义它们的属性。动态字段和普通字段之间的关键区别在于前者不须要在 schema.xml 中提早声明名称。Solr 将名称声明中的 glob-like 模式应用到全部还没有声明的引入的字段名称,并根据其 <dynamicField> 声明定义的语义来处理字段。例如,<dynamicField name="*_i" type="sint" indexed="true" stored="true"/> 指一个 myRating_i 字段被 Solr 处理为 sint,尽管并未将其声明为字段。这种处理比较方便,例如,当须要用户定义待搜索内容的时候。

 

五、 索引配置

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

表 1 归纳了可控制 Solr 索引处理的各类因素:

因素

描述

useCompoundFile

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

mergeFactor

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

maxBufferedDocs

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

maxMergeDocs

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

maxFieldLength

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

unlockOnStartup

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

 

六、 查询处理配置

<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 文件中的注释。

 

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

用于监视、记录和统计数据的 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 中运行的全部线程的堆栈跟踪信息。

 

八、 智能缓存

智能缓存是让 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 会更多,只不过须要花更长的预热时间。

 

3、利用SolrJ操做solr API,完成index操做

使用SolrJ操做Solr会比利用httpClient来操做Solr要简单。SolrJ是封装了httpClient方法,来操做solr的API的。SolrJ底层仍是经过使用httpClient中的方法来完成Solr的操做。

一、 首先,你须要添加以下jar包

clip_image012

其中apache-solr-solrj-3.4.0.jar、slf4j-api-1.6.1.jar能够在下载的apache-solr-3.4.0的压缩包中的dist中能找到。

 

二、 其次,创建一个简单的测试类,完成Server对象的相关方法的测试工做,代码以下:

package com.hoo.test;
 
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.CommonsHttpSolrServer;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.client.solrj.response.UpdateResponse;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.params.SolrParams;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.hoo.entity.Index;
 
/**
 * <b>function:</b> Server TestCase
 * @author hoojo
 * @createDate 2011-10-19 下午01:49:07
 * @file ServerTest.java
 * @package com.hoo.test
 * @project SolrExample
 * @blog http://blog.csdn.net/IBM_hoojo
 * @email hoojo_@126.com
 * @version 1.0
 */
public class ServerTest {
    
    private SolrServer server;
    private CommonsHttpSolrServer httpServer;
    
    private static final String DEFAULT_URL = "http://localhost:8983/solr/";
    
    @Before
    public void init() {
        try {
            server = new CommonsHttpSolrServer(DEFAULT_URL);
            httpServer = new CommonsHttpSolrServer(DEFAULT_URL);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
    }
    
    @After
    public void destory() {
        server = null;
        httpServer = null;
        System.runFinalization();
        System.gc();
    }
    
    public final void fail(Object o) {
        System.out.println(o);
    }
    
    /**
     * <b>function:</b> 测试是否建立server对象成功
     * @author hoojo
     * @createDate 2011-10-21 上午09:48:18
     */
    @Test
    public void server() {
        fail(server);
        fail(httpServer);
    }
 
    /**
     * <b>function:</b> 根据query参数查询索引
     * @author hoojo
     * @createDate 2011-10-21 上午10:06:39
     * @param query
     */
    public void query(String query) {
        SolrParams params = new SolrQuery(query);
        
        try {
            QueryResponse response = server.query(params);
            
            SolrDocumentList list = response.getResults();
            for (int i = 0; i < list.size(); i++) {
                fail(list.get(i));
            }
        } catch (SolrServerException e) {
            e.printStackTrace();
        } 
    }
}

测试运行server case方法,若是成功建立对象,那你就成功的连接到。

注意:在运行本方法以前,请启动你的solr官方自动的项目。http://localhost:8983/solr/保证可以成功访问这个工程。由于接下来的全部工做都是围绕这个solr工程完成的。若是你如今还不知道,怎么部署、发布官方solr工程,请参考前面的具体章节。

 

三、 Server的有关配置选项参数,server是CommonsHttpSolrServer的实例

server.setSoTimeout(1000); // socket read timeout 
server.setConnectionTimeout(100); 
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. 
 
//sorlr J 目前使用二进制的格式做为默认的格式。对于solr1.2的用户经过显示的设置才能使用XML格式。
server.setParser(new XMLResponseParser());
 
//二进制流输出格式
//server.setRequestWriter(new BinaryRequestWriter());

 

四、 利用SolrJ完成Index Document的添加操做

/**
 * <b>function:</b> 添加doc文档
 * @author hoojo
 * @createDate 2011-10-21 上午09:49:10
 */
@Test
public void addDoc() {
    //建立doc文档
     SolrInputDocument doc = new SolrInputDocument();
    doc.addField("id", 1);
    doc.addField("name", "Solr Input Document");
    doc.addField("manu", "this is SolrInputDocument content");
    
    try {
        //添加一个doc文档
        UpdateResponse response = server.add(doc);
        fail(server.commit());//commit后才保存到索引库
        fail(response);
        fail("query time:" + response.getQTime());
        fail("Elapsed Time:" + response.getElapsedTime());
        fail("status:" + response.getStatus());
    } catch (SolrServerException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    query("name:solr");
}

在apache-solr-3.4.0\example\solr\conf目录下的schema.xml中能够找到有关于field属性的配置,schema.xml中的field就和上面Document文档中的field(id、name、manu)对应。若是出现ERROR:unknown field 'xxxx'就表示你设置的这个field在schema.xml中不存在。若是必定要使用这个field,请你在schema.xml中进行filed元素的配置。具体请参考前面的章节。

注意:在schema.xml中配置了uniqueKey为id,就表示id是惟一的。若是在添加Document的时候,id重复添加。那么后面添加的相同id的doc会覆盖前面的doc,相似于update更新操做,而不会出现重复的数据。

 

五、 利用SolrJ添加多个Document,即添加文档集合

/**
 * <b>function:</b> 添加docs文档集合
 * @author hoojo
 * @createDate 2011-10-21 上午09:55:01
 */
@Test
public void addDocs() {
    Collection<SolrInputDocument> docs = new ArrayList<SolrInputDocument>();
    
    SolrInputDocument doc = new SolrInputDocument();
    doc.addField("id", 2);
    doc.addField("name", "Solr Input Documents 1");
    doc.addField("manu", "this is SolrInputDocuments 1 content");
    
    docs.add(doc);
    
    doc = new SolrInputDocument();
    doc.addField("id", 3);
    doc.addField("name", "Solr Input Documents 2");
    doc.addField("manu", "this is SolrInputDocuments 3 content");
    
    docs.add(doc);
    
    try {
        //add docs
        UpdateResponse response = server.add(docs);
        //commit后才保存到索引库
        fail(server.commit());
        fail(response);
    } catch (SolrServerException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    query("solr");
}

就是添加一个List集合

 

六、 添加JavaEntity Bean,这个须要先建立一个JavaBean,而后来完成添加操做;

JavaBean:Index的代码

package com.hoo.entity;
 
import org.apache.solr.client.solrj.beans.Field;
 
/**
 * <b>function:</b> JavaEntity Bean;Index须要添加相关的Annotation注解,便于告诉solr哪些属性参与到index中
 * @author hoojo
 * @createDate 2011-10-19 下午05:33:27
 * @file Index.java
 * @package com.hoo.entity
 * @project SolrExample
 * @blog http://blog.csdn.net/IBM_hoojo
 * @email hoojo_@126.com
 * @version 1.0
 */
public class Index {
    //@Field setter方法上添加Annotation也是能够的
    private String id;
    @Field
    private String name;
    @Field
    private String manu;
    @Field
    private String[] cat;
 
    @Field
    private String[] features;
    @Field
    private float price;
    @Field
    private int popularity;
    @Field
    private boolean inStock;
    
    public String getId() {
        return id;
    }
    
    @Field
    public void setId(String id) {
        this.id = id;
    }
    //getter、setter方法
 
    public String toString() {
        return this.id + "#" + this.name + "#" + this.manu + "#" + this.cat;
    }
}

注意上面的属性是和在apache-solr-3.4.0\example\solr\conf目录下的schema.xml中能够找到有关于field属性的配置对应的。若是你Index JavaBean中出现的属性在schema.xml的field配置没法找到,那么出出现unknown filed错误。

添加Bean完成doc添加操做

/**
 * <b>function:</b> 添加JavaEntity Bean
 * @author hoojo
 * @createDate 2011-10-21 上午09:55:37
 */
@Test
public void addBean() {
    //Index须要添加相关的Annotation注解,便于告诉solr哪些属性参与到index中
    Index index = new Index();
    index.setId("4");
    index.setName("add bean index");
    index.setManu("index bean manu");
    index.setCat(new String[] { "a1", "b2" });
    
    try {
        //添加Index Bean到索引库
        UpdateResponse response = server.addBean(index);
        fail(server.commit());//commit后才保存到索引库
        fail(response);
    } catch (SolrServerException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    queryAll();
}

 

七、 添加Bean集合

/**
 * <b>function:</b> 添加Entity Bean集合到索引库
 * @author hoojo
 * @createDate 2011-10-21 上午10:00:55
 */
@Test
public void addBeans() {
    Index index = new Index();
    index.setId("6");
    index.setName("add beans index 1");
    index.setManu("index beans manu 1");
    index.setCat(new String[] { "a", "b" });
    
    List<Index> indexs = new ArrayList<Index>();
    indexs.add(index);
    
    index = new Index();
    index.setId("5");
    index.setName("add beans index 2");
    index.setManu("index beans manu 2");
    index.setCat(new String[] { "aaa", "bbbb" });
    indexs.add(index);
    try {
        //添加索引库
        UpdateResponse response = server.addBeans(indexs);
        fail(server.commit());//commit后才保存到索引库
        fail(response);
    } catch (SolrServerException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    queryAll();
}

 

八、 删除索引Document

/**
 * <b>function:</b> 删除索引操做
 * @author hoojo
 * @createDate 2011-10-21 上午10:04:28
 */
@Test
public void remove() {
    try {
        //删除id为1的索引
        server.deleteById("1");
        server.commit();
        query("id:1");
        
        //根据id集合,删除多个索引
        List<String> ids = new ArrayList<String>();
        ids.add("2");
        ids.add("3");
        server.deleteById(ids);
        server.commit(true, true);
        query("id:3 id:2");
        
        //删除查询到的索引信息
        server.deleteByQuery("id:4 id:6");
        server.commit(true, true);
        queryAll();
        
    } catch (SolrServerException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

 

九、 查询索引

/**
 * <b>function:</b> 查询全部索引信息
 * @author hoojo
 * @createDate 2011-10-21 上午10:05:38
 */
@Test
public void queryAll() {
    ModifiableSolrParams params = new ModifiableSolrParams();
    // 查询关键词,*:*表明全部属性、全部值,即全部index
    params.set("q", "*:*");
    // 分页,start=0就是从0开始,,rows=5当前返回5条记录,第二页就是变化start这个值为5就能够了。
    params.set("start", 0);
    params.set("rows", Integer.MAX_VALUE);
    
    // 排序,,若是按照id 排序,,那么将score desc 改为 id desc(or asc)
    params.set("sort", "score desc");
 
    // 返回信息 * 为所有 这里是所有加上score,若是不加下面就不能使用score
    params.set("fl", "*,score");
    
    try {
        QueryResponse response = server.query(params);
        
        SolrDocumentList list = response.getResults();
        for (int i = 0; i < list.size(); i++) {
            fail(list.get(i));
        }
    } catch (SolrServerException e) {
        e.printStackTrace();
    }
}

 

十、 其余和Server有关方法

/**
 * <b>function:</b> 其余server相关方法测试
 * @author hoojo
 * @createDate 2011-10-21 上午10:02:03
 */
@Test
public void otherMethod() {
    fail(server.getBinder());
    try {
        fail(server.optimize());//合并索引文件,能够优化索引、提供性能,但须要必定的时间
        fail(server.ping());//ping服务器是否链接成功
        
        Index index = new Index();
        index.setId("299");
        index.setName("add bean index199");
        index.setManu("index bean manu199");
        index.setCat(new String[] { "a199", "b199" });
        
        UpdateResponse response = server.addBean(index);
        fail("response: " + response);
        
        queryAll();
        //回滚掉以前的操做,rollback addBean operation
        fail("rollback: " + server.rollback());
        //提交操做,提交后没法回滚以前操做;发现addBean没有成功添加索引
        fail("commit: " + server.commit());
        queryAll();
    } catch (SolrServerException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

 

十一、 文档查询

/**
 * <b>function:</b> query 基本用法测试
 * @author hoojo
 * @createDate 2011-10-20 下午04:44:28
 */
@Test
public void queryCase() {
    //AND 而且
    SolrQuery params = new SolrQuery("name:apple AND manu:inc");
    
    //OR 或者
    params.setQuery("name:apple OR manu:apache");
    //空格 等同于 OR
    params.setQuery("name:server manu:dell");
    
    //params.setQuery("name:solr - manu:inc");
    //params.setQuery("name:server + manu:dell");
    
    //查询name包含solr apple
    params.setQuery("name:solr,apple");
    //manu不包含inc
    params.setQuery("name:solr,apple NOT manu:inc");
    
    //50 <= price <= 200
    params.setQuery("price:[50 TO 200]");
    params.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
    params.setQuery("price:[50 TO 200] AND popularity:[5 TO 6]");
    params.setQuery("price:[50 TO 200] OR popularity:[5 TO 6]");
    
    //过滤器查询,能够提升性能 filter 相似多个条件组合,如and
    //params.addFilterQuery("id:VA902B");
    //params.addFilterQuery("price:[50 TO 200]");
    //params.addFilterQuery("popularity:[* TO 5]");
    //params.addFilterQuery("weight:*");
    //0 < popularity < 6  没有等于
    //params.addFilterQuery("popularity:{0 TO 6}");
    
    //排序
    params.addSortField("id", ORDER.asc);
    
    //分页:start开始页,rows每页显示记录条数
    //params.add("start", "0");
    //params.add("rows", "200");
    //params.setStart(0);
    //params.setRows(200);
    
    //设置高亮
    params.setHighlight(true); // 开启高亮组件
    params.addHighlightField("name");// 高亮字段
    params.setHighlightSimplePre("<font color='red'>");//标记,高亮关键字前缀
    params.setHighlightSimplePost("</font>");//后缀
    params.setHighlightSnippets(1);//结果分片数,默认为1
    params.setHighlightFragsize(1000);//每一个分片的最大长度,默认为100
 
    //分片信息
    params.setFacet(true)
        .setFacetMinCount(1)
        .setFacetLimit(5)//段
        .addFacetField("name")//分片字段
        .addFacetField("inStock"); 
    
    //params.setQueryType("");
    
    try {
        QueryResponse response = server.query(params);
        
        /*List<Index> indexs = response.getBeans(Index.class);
        for (int i = 0; i < indexs.size(); i++) {
            fail(indexs.get(i));
        }*/
        
        //输出查询结果集
        SolrDocumentList list = response.getResults();
        fail("query result nums: " + list.getNumFound());
        for (int i = 0; i < list.size(); i++) {
            fail(list.get(i));
        }
        
        //输出分片信息
        List<FacetField> facets = response.getFacetFields();
        for (FacetField facet : facets) {
            fail(facet);
            List<Count> facetCounts = facet.getValues();
            for (FacetField.Count count : facetCounts) {
                System.out.println(count.getName() + ": " + count.getCount());
            }
        }
    } catch (SolrServerException e) {
        e.printStackTrace();
    } 
}

 

十二、 分片查询、统计

/**
 * <b>function:</b> 分片查询, 能够统计关键字及出现的次数、或是作自动补全提示
 * @author hoojo
 * @createDate 2011-10-20 下午04:54:25
 */
@Test
public void facetQueryCase() {
    SolrQuery params = new SolrQuery("*:*");
    
    //排序
    params.addSortField("id", ORDER.asc);
    
    params.setStart(0);
    params.setRows(200);
 
    //Facet为solr中的层次分类查询
    //分片信息
    params.setFacet(true)
        .setQuery("*:*")
        .setFacetMinCount(1)
        .setFacetLimit(5)//段
        //.setFacetPrefix("electronics", "cat")
        .setFacetPrefix("cor")//查询manu、name中关键字前缀是cor的
        .addFacetField("manu")
        .addFacetField("name");//分片字段
 
    try {
        QueryResponse response = server.query(params);
        
        //输出查询结果集
        SolrDocumentList list = response.getResults();
        fail("Query result nums: " + list.getNumFound());
        
        for (int i = 0; i < list.size(); i++) {
            fail(list.get(i));
        }
        
        fail("All facet filed result: ");
        //输出分片信息
        List<FacetField> facets = response.getFacetFields();
        for (FacetField facet : facets) {
            fail(facet);
            List<Count> facetCounts = facet.getValues();
            for (FacetField.Count count : facetCounts) {
                //关键字 - 出现次数
                fail(count.getName() + ": " + count.getCount());
            }
        }
        
        fail("Search facet [name] filed result: ");
        //输出分片信息
        FacetField facetField = response.getFacetField("name");
        List<Count> facetFields = facetField.getValues();
        for (Count count : facetFields) {
            //关键字 - 出现次数
            fail(count.getName() + ": " + count.getCount());
        }
    } catch (SolrServerException e) {
        e.printStackTrace();
    } 
}

分片查询在某些统计关键字的时候仍是颇有用的,能够统计关键字出现的次数,能够经过统计的关键字来搜索相关文档的信息。

 

4、Document文档和JavaBean相互转换

这里转换的Bean是一个简单的User对象

package com.hoo.entity;
 
import java.io.Serializable;
import org.apache.solr.client.solrj.beans.Field;
 
/**
 * <b>function:</b> User Entity Bean;全部被添加Annotation @Field 注解的属性将参与index操做
 * @author hoojo
 * @createDate 2011-10-19 下午04:16:00
 * @file User.java
 * @package com.hoo.entity
 * @project SolrExample
 * @blog http://blog.csdn.net/IBM_hoojo
 * @email hoojo_@126.com
 * @version 1.0
 */
public class User implements Serializable {
 
    /**
     * @author Hoojo
     */
    private static final long serialVersionUID = 8606788203814942679L;
 
    //@Field
    private int id;
    @Field
    private String name;
    @Field
    private int age;
    
    /**
     * 能够给某个属性重命名,likes就是solr index的属性;在solrIndex中将显示like为likes
     */
    @Field("likes")
    private String[] like;
    @Field
    private String address;
    @Field
    private String sex;
    @Field
    private String remark;
    public int getId() {
        return id;
    }
    
    //setter 方法上面也能够
    @Field
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    //getter、setter
    
    @Override
    public String toString() {
        return this.id + "#" + this.name + "#" + this.age + "#" + this.like + "#" + this.address + "#" + this.sex + "#" + this.remark;
    }
}

 

测试类代码以下

package com.hoo.test;
 
import org.apache.solr.client.solrj.beans.DocumentObjectBinder;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.SolrInputField;
import org.junit.Test;
import com.hoo.entity.User;
 
/**
 * <b>function:</b>SolrInputDocument implements Map, Iterable
 * @author hoojo
 * @createDate 2011-10-19 下午03:54:54
 * @file SolrInputDocumentTest.java
 * @package com.hoo.test
 * @project SolrExample
 * @blog http://blog.csdn.net/IBM_hoojo
 * @email hoojo_@126.com
 * @version 1.0
 */
public class SolrInputDocumentTest {
 
    public final void fail(Object o) {
        System.out.println(o);
    }
    
    /**
     * <b>function:</b> 建立SolrInputDocument
     * @author hoojo
     * @createDate 2011-10-21 下午03:38:20
     */
    @Test
    public void createDoc() {
        SolrInputDocument doc = new SolrInputDocument();
        doc.addField("id", System.currentTimeMillis());
        doc.addField("name", "SolrInputDocument");
        doc.addField("age", 22, 2.0f);
        
        doc.addField("like", new String[] { "music", "book", "sport" });
        
        doc.put("address", new SolrInputField("guangzhou"));
        
        doc.setField("sex", "man");
        doc.setField("remark", "china people", 2.0f);
        
        fail(doc);
    }
    
    /**
     * <b>function:</b> 利用DocumentObjectBinder对象将SolrInputDocument 和 User对象相互转换
     * @author hoojo
     * @createDate 2011-10-21 下午03:38:40
     */
    @Test
    public void docAndBean4Binder() {
        SolrDocument doc = new SolrDocument();
        doc.addField("id", 456);
        doc.addField("name", "SolrInputDocument");
        
        doc.addField("likes", new String[] { "music", "book", "sport" });
        
        doc.put("address", "guangzhou");
        
        doc.setField("sex", "man");
        doc.setField("remark", "china people");
        
        DocumentObjectBinder binder = new DocumentObjectBinder();
        
        User user = new User();
        user.setId(222);
        user.setName("JavaBean");
        user.setLike(new String[] { "music", "book", "sport" });
        user.setAddress("guangdong");
        
        fail(doc);
        // User ->> SolrInputDocument
        fail(binder.toSolrInputDocument(user));
        // SolrDocument ->> User
        fail(binder.getBean(User.class, doc));
        
        SolrDocumentList list = new SolrDocumentList();
        list.add(doc);
        list.add(doc);
        //SolrDocumentList ->> List
        fail(binder.getBeans(User.class, list));
    }
    
    /**
     * <b>function:</b> SolrInputDocument的相关方法
     * @author hoojo
     * @createDate 2011-10-21 下午03:44:30
     */
    @Test
    public void docMethod() {
        SolrInputDocument doc = new SolrInputDocument();
        doc.addField("id", System.currentTimeMillis());
        doc.addField("name", "SolrInputDocument");
        doc.addField("age", 23, 1.0f);
        doc.addField("age", 22, 2.0f);
        doc.addField("age", 24, 0f);
        
        fail(doc.entrySet());
        fail(doc.get("age"));
        //排名有用,相似百度竞价排名
        doc.setDocumentBoost(2.0f);
        fail(doc.getDocumentBoost());
        fail(doc.getField("name"));
        fail(doc.getFieldNames());//keys
        fail(doc.getFieldValues("age"));
        fail(doc.getFieldValues("id"));
        fail(doc.values());
    }
}
相关文章
相关标签/搜索