您的位置:首页 > 运维架构 > Tomcat

solr+tomcat例子

2014-04-14 00:03 381 查看


Solr开发文档

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

开发环境:

System:Windows

WebBrowser:IE6+、Firefox3+

JDK:1.6+

JavaEEServer:tomcat5.0.2.8、tomcat6

IDE:eclipse、MyEclipse8

开发依赖库:

JavaEE5、solr3.4

个人博客:

http://hoojo.cnblogs.com

http://blog.csdn.net/IBM_hoojo

email:hoojo_@126.com


一、配置和安装solr

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

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

目前最新的是3.4的版本

2、下载后解压目录如下





client是一个ruby实现的示例,这个我们暂时不管

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

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

docs是帮助文档

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

3、发布、部署solr示例

A、利用自带的Jetty服务器

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

cdE:\JAR\solr\apache-solr-3.4.0\example

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





启动Jetty成功后,如果没有看到错误消息,你可以看到端口信息。





如果你的端口冲突了,你可以到解压的solr示例包的example/etc的jetty.xml中,修改端口port信息。

<Setname="port">

<SystemPropertyname="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配置,配置如下:

<ContextdocBase="D:\solr.war"debug="0"crossContext="true">

<Environmentname="solr/home"type="java.lang.String"value="D:\solr"override="true"/>

</Context>


上面的2步都是一样的,这样还没有完。启动后你可能会看到如下错误:





我们需要将一些配置和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了。

4、这个时候你就可以访问http://localhost:8983/solr/admin/你就可以看到如下界面:





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

<?xmlversion="1.0"encoding="UTF-8"?>

<response>

<lstname="responseHeader">

<intname="status">0</int>

<intname="QTime">0</int>

<lstname="params">

<strname="indent">on</str>

<strname="start">0</str>

<strname="q">solr</str>

<strname="version">2.2</str>

<strname="rows">10</str>

</lst>

</lst>

<resultname="response"numFound="1"start="0">

<doc>

<arrname="cat"><str>software</str><str>search</str></arr>

<arrname="features"><str>AdvancedFull-TextSearchCapabilitiesusingLucene</str><str>OptimizedforHighVolumeWebTraffic</str><str>StandardsBasedOpenInterfaces-XMLandHTTP</str>

<str>ComprehensiveHTMLAdministrationInterfaces</str><str>Scalability-EfficientReplicationtootherSolrSearchServers</str><str>FlexibleandAdaptablewithXMLconfigurationandSchema</str><str>Goodunicodesupport:h¨¦llo(hellowithanaccentoverthee)</str></arr>

<strname="id">SOLR1000</str>

<boolname="inStock">true</bool>

<datename="incubationdate_dt">2006-01-17T00:00:00Z</date>

<strname="manu">ApacheSoftwareFoundation</str>

<strname="name">Solr,theEnterpriseSearchServer</str>

<intname="popularity">10</int>

<floatname="price">0.0</float>

</doc>

</result>

</response>




二、Solr理论

1、solr基础

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

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

描述

Indexed

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

Stored

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

2、solr索引操作

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

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

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

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

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

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

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

3、搜索

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

solr查询参数描述:
参数

描述

示例

q

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

q=myField:JavaANDotherField:developerWorks;dateasc

此查询搜索指定的两个字段,并根据一个日期字段对结果进行排序。

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=dateasc,pricedesc

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)

schema配置类型

<fieldTypename="text"class="solr.TextField"positionIncrementGap="100">

<analyzertype="index">

<tokenizerclass="solr.WhitespaceTokenizerFactory"/>

<filterclass="solr.StopFilterFactory"ignoreCase="true"

words="stopwords.txt"/>

<filterclass="solr.WordDelimiterFilterFactory"

generateWordParts="1"generateNumberParts="1"catenateWords="1"

catenateNumbers="1"catenateAll="0"/>

<filterclass="solr.LowerCaseFilterFactory"/>

<filterclass="solr.EnglishPorterFilterFactory"protected="protwords.txt"/>

<filterclass="solr.RemoveDuplicatesTokenFilterFactory"/>

</analyzer>

<analyzertype="query">

<tokenizerclass="solr.WhitespaceTokenizerFactory"/>

<filterclass="solr.SynonymFilterFactory"synonyms="synonyms.txt"

ignoreCase="true"expand="true"/>

<filterclass="solr.StopFilterFactory"ignoreCase="true"

words="stopwords.txt"/>

<filterclass="solr.WordDelimiterFilterFactory"

generateWordParts="1"generateNumberParts="1"catenateWords="0"

catenateNumbers="0"catenateAll="0"/>

<filterclass="solr.LowerCaseFilterFactory"/>

<filterclass="solr.EnglishPorterFilterFactory"protected="protwords.txt"/>

<filterclass="solr.RemoveDuplicatesTokenFilterFactory"/>

</analyzer>

</fieldType>


上面就是一个type了,然后你在fields配置field的时候就可以用这个type。

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

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

Ø根据空白进行断词,然后删除所有的公共词(StopFilterFactory)

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

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

Ø删除所有的副本(RemoveDuplicatesTokenFilterFactory)

Schema属性、字段

<fieldname="id"type="string"indexed="true"stored="true"

required="true"/>

<fieldname="sku"type="text_en_splitting_tight"indexed="true"

stored="true"omitNorms="true"/>

<fieldname="name"type="text_general"indexed="true"stored="true"/>

<fieldname="alphaNameSort"type="alphaOnlySort"indexed="true"

stored="false"/>

<fieldname="manu"type="text_general"indexed="true"stored="true"

omitNorms="true"/>

<fieldname="cat"type="string"indexed="true"stored="true"

multiValued="true"/>

<fieldname="features"type="text_general"indexed="true"stored="true"

multiValued="true"/>

<fieldname="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>声明定义的语义来处理字段。例如,<dynamicFieldname="*_i"type="sint"indexed="true"stored="true"/>
指一个myRating_i字段被Solr处理为sint,尽管并未将其声明为字段。这种处理比较方便,例如,当需要用户定义待搜索内容的时候。

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的版本以及在当前实现中进行查询、更新和缓存所使用的类的详细信息。此外,还包括文件存于Solrsubversion存储库的何处的信息以及对该文件功能的一个简要描述。

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文件。

Threaddump

http://localhost:8080/solr/admin/threaddump.jsp
threaddump选项显示了在JVM中运行的所有线程的堆栈跟踪信息。

8、智能缓存

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

描述

能否自热

filterCache

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

可以

queryResultCache

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

可以

documentCache

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

不可以

Namedcaches

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

可以,

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

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

class是缓存实现的Java名。

size是最大的条目数。

initialSize是缓存的初始大小。

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



三、利用SolrJ操作solrAPI,完成index操作

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

1、首先,你需要添加如下jar包





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

2、其次,建立一个简单的测试类,完成Server对象的相关方法的测试工作,代码如下:

packagecom.hoo.test;


importjava.io.IOException;

importjava.net.MalformedURLException;

importjava.util.ArrayList;

importjava.util.Collection;

importjava.util.List;

importorg.apache.solr.client.solrj.SolrQuery;

importorg.apache.solr.client.solrj.SolrServer;

importorg.apache.solr.client.solrj.SolrServerException;

importorg.apache.solr.client.solrj.impl.CommonsHttpSolrServer;

importorg.apache.solr.client.solrj.response.QueryResponse;

importorg.apache.solr.client.solrj.response.UpdateResponse;

importorg.apache.solr.common.SolrDocumentList;

importorg.apache.solr.common.SolrInputDocument;

importorg.apache.solr.common.params.ModifiableSolrParams;

importorg.apache.solr.common.params.SolrParams;

importorg.junit.After;

importorg.junit.Before;

importorg.junit.Test;

importcom.hoo.entity.Index;


/**

*<b>function:</b>ServerTestCase

*@authorhoojo

*@createDate2011-10-19下午01:49:07

*@fileServerTest.java

*@packagecom.hoo.test

*@projectSolrExample

*@blog'target='_blank'>http://blog.csdn.net/IBM_hoojo[/code]
*@emailhoojo_@126.com

*@version1.0

*/

publicclassServerTest{


privateSolrServerserver;

privateCommonsHttpSolrServerhttpServer;


privatestaticfinalStringDEFAULT_URL="http://localhost:8983/solr/";


@Before

publicvoidinit(){

try{

server=newCommonsHttpSolrServer(DEFAULT_URL);

httpServer=newCommonsHttpSolrServer(DEFAULT_URL);

}catch(MalformedURLExceptione){

e.printStackTrace();

}

}


@After

publicvoiddestory(){

server=null;

httpServer=null;

System.runFinalization();

System.gc();

}


publicfinalvoidfail(Objecto){

System.out.println(o);

}


/**

*<b>function:</b>测试是否创建server对象成功

*@authorhoojo

*@createDate2011-10-21上午09:48:18

*/

@Test

publicvoidserver(){

fail(server);

fail(httpServer);

}


/**

*<b>function:</b>根据query参数查询索引

*@authorhoojo

*@createDate2011-10-21上午10:06:39

*@paramquery

*/

publicvoidquery(Stringquery){

SolrParamsparams=newSolrQuery(query);


try{

QueryResponseresponse=server.query(params);


SolrDocumentListlist=response.getResults();

for(inti=0;i<list.size();i++){

fail(list.get(i));

}

}catch(SolrServerExceptione){

e.printStackTrace();

}

}

}


测试运行servercase方法,如果成功创建对象,那你就成功的链接到。

注意:在运行本方法之前,请启动你的solr官方自动的项目。http://localhost:8983/solr/保证能够成功访问这个工程。因为接下来的所有工作都是围绕这个solr工程完成的。如果你现在还不知道,怎么部署、发布官方solr工程,请参考前面的具体章节。

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

server.setSoTimeout(1000);//socketreadtimeout

server.setConnectionTimeout(100);

server.setDefaultMaxConnectionsPerHost(100);

server.setMaxTotalConnections(100);

server.setFollowRedirects(false);//defaultstofalse

//allowCompressiondefaultstofalse.

//Serversidemustsupportgzipordeflateforthistohaveanyeffect.

server.setAllowCompression(true);

server.setMaxRetries(1);//defaultsto0.>1notrecommended.


//sorlrJ目前使用二进制的格式作为默认的格式。对于solr1.2的用户通过显示的设置才能使用XML格式。

server.setParser(newXMLResponseParser());


//二进制流输出格式

//server.setRequestWriter(newBinaryRequestWriter());


4、利用SolrJ完成IndexDocument的添加操作

/**

*<b>function:</b>添加doc文档

*@authorhoojo

*@createDate2011-10-21上午09:49:10

*/

@Test

publicvoidaddDoc(){

//创建doc文档

SolrInputDocumentdoc=newSolrInputDocument();

doc.addField("id",1);

doc.addField("name","SolrInputDocument");

doc.addField("manu","thisisSolrInputDocumentcontent");


try{

//添加一个doc文档

UpdateResponseresponse=server.add(doc);

fail(server.commit());//commit后才保存到索引库

fail(response);

fail("querytime:"+response.getQTime());

fail("ElapsedTime:"+response.getElapsedTime());

fail("status:"+response.getStatus());

}catch(SolrServerExceptione){

e.printStackTrace();

}catch(IOExceptione){

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:unknownfield'xxxx'就表示你设置的这个field在schema.xml中不存在。如果一定要使用这个field,请你在schema.xml中进行filed元素的配置。具体请参考前面的章节。

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

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

/**

*<b>function:</b>添加docs文档集合

*@authorhoojo

*@createDate2011-10-21上午09:55:01

*/

@Test

publicvoidaddDocs(){

Collection<SolrInputDocument>docs=newArrayList<SolrInputDocument>();


SolrInputDocumentdoc=newSolrInputDocument();

doc.addField("id",2);

doc.addField("name","SolrInputDocuments1");

doc.addField("manu","thisisSolrInputDocuments1content");


docs.add(doc);


doc=newSolrInputDocument();

doc.addField("id",3);

doc.addField("name","SolrInputDocuments2");

doc.addField("manu","thisisSolrInputDocuments3content");


docs.add(doc);


try{

//adddocs

UpdateResponseresponse=server.add(docs);

//commit后才保存到索引库

fail(server.commit());

fail(response);

}catch(SolrServerExceptione){

e.printStackTrace();

}catch(IOExceptione){

e.printStackTrace();

}

query("solr");

}


就是添加一个List集合

6、添加JavaEntityBean,这个需要先创建一个JavaBean,然后来完成添加操作;

JavaBean:Index的代码

packagecom.hoo.entity;


importorg.apache.solr.client.solrj.beans.Field;


/**

*<b>function:</b>JavaEntityBean;Index需要添加相关的Annotation注解,便于告诉solr哪些属性参与到index中

*@authorhoojo

*@createDate2011-10-19下午05:33:27

*@fileIndex.java

*@packagecom.hoo.entity

*@projectSolrExample

*@blog'target='_blank'>http://blog.csdn.net/IBM_hoojo[/code]
*@emailhoojo_@126.com

*@version1.0

*/

publicclassIndex{

//@Fieldsetter方法上添加Annotation也是可以的

privateStringid;

@Field

privateStringname;

@Field

privateStringmanu;

@Field

privateString[]cat;


@Field

privateString[]features;

@Field

privatefloatprice;

@Field

privateintpopularity;

@Field

privatebooleaninStock;


publicStringgetId(){

returnid;

}


@Field

publicvoidsetId(Stringid){

this.id=id;

}

//getter、setter方法


publicStringtoString(){

returnthis.id+"#"+this.name+"#"+this.manu+"#"+this.cat;

}

}


注意上面的属性是和在apache-solr-3.4.0\example\solr\conf目录下的schema.xml中可以找到有关于field属性的配置对应的。如果你IndexJavaBean中出现的属性在schema.xml的field配置无法找到,那么出出现unknownfiled错误。

添加Bean完成doc添加操作

/**

*<b>function:</b>添加JavaEntityBean

*@authorhoojo

*@createDate2011-10-21上午09:55:37

*/

@Test

publicvoidaddBean(){

//Index需要添加相关的Annotation注解,便于告诉solr哪些属性参与到index中

Indexindex=newIndex();

index.setId("4");

index.setName("addbeanindex");

index.setManu("indexbeanmanu");

index.setCat(newString[]{"a1","b2"});


try{

//添加IndexBean到索引库

UpdateResponseresponse=server.addBean(index);

fail(server.commit());//commit后才保存到索引库

fail(response);

}catch(SolrServerExceptione){

e.printStackTrace();

}catch(IOExceptione){

e.printStackTrace();

}

queryAll();

}


7、添加Bean集合

/**

*<b>function:</b>添加EntityBean集合到索引库

*@authorhoojo

*@createDate2011-10-21上午10:00:55

*/

@Test

publicvoidaddBeans(){

Indexindex=newIndex();

index.setId("6");

index.setName("addbeansindex1");

index.setManu("indexbeansmanu1");

index.setCat(newString[]{"a","b"});


List<Index>indexs=newArrayList<Index>();

indexs.add(index);


index=newIndex();

index.setId("5");

index.setName("addbeansindex2");

index.setManu("indexbeansmanu2");

index.setCat(newString[]{"aaa","bbbb"});

indexs.add(index);

try{

//添加索引库

UpdateResponseresponse=server.addBeans(indexs);

fail(server.commit());//commit后才保存到索引库

fail(response);

}catch(SolrServerExceptione){

e.printStackTrace();

}catch(IOExceptione){

e.printStackTrace();

}

queryAll();

}


8、删除索引Document

/**

*<b>function:</b>删除索引操作

*@authorhoojo

*@createDate2011-10-21上午10:04:28

*/

@Test

publicvoidremove(){

try{

//删除id为1的索引

server.deleteById("1");

server.commit();

query("id:1");


//根据id集合,删除多个索引

List<String>ids=newArrayList<String>();

ids.add("2");

ids.add("3");

server.deleteById(ids);

server.commit(true,true);

query("id:3id:2");


//删除查询到的索引信息

server.deleteByQuery("id:4id:6");

server.commit(true,true);

queryAll();


}catch(SolrServerExceptione){

e.printStackTrace();

}catch(IOExceptione){

e.printStackTrace();

}

}


9、查询索引

/**

*<b>function:</b>查询所有索引信息

*@authorhoojo

*@createDate2011-10-21上午10:05:38

*/

@Test

publicvoidqueryAll(){

ModifiableSolrParamsparams=newModifiableSolrParams();

//查询关键词,*:*代表所有属性、所有值,即所有index

params.set("q","*:*");

//分页,start=0就是从0开始,,rows=5当前返回5条记录,第二页就是变化start这个值为5就可以了。

params.set("start",0);

params.set("rows",Integer.MAX_VALUE);


//排序,,如果按照id排序,,那么将scoredesc改成iddesc(orasc)

params.set("sort","scoredesc");


//返回信息*为全部这里是全部加上score,如果不加下面就不能使用score

params.set("fl","*,score");


try{

QueryResponseresponse=server.query(params);


SolrDocumentListlist=response.getResults();

for(inti=0;i<list.size();i++){

fail(list.get(i));

}

}catch(SolrServerExceptione){

e.printStackTrace();

}

}


10、其他和Server有关方法

/**

*<b>function:</b>其他server相关方法测试

*@authorhoojo

*@createDate2011-10-21上午10:02:03

*/

@Test

publicvoidotherMethod(){

fail(server.getBinder());

try{

fail(server.optimize());//合并索引文件,可以优化索引、提供性能,但需要一定的时间

fail(server.ping());//ping服务器是否连接成功


Indexindex=newIndex();

index.setId("299");

index.setName("addbeanindex199");

index.setManu("indexbeanmanu199");

index.setCat(newString[]{"a199","b199"});


UpdateResponseresponse=server.addBean(index);

fail("response:"+response);


queryAll();

//回滚掉之前的操作,rollbackaddBeanoperation

fail("rollback:"+server.rollback());

//提交操作,提交后无法回滚之前操作;发现addBean没有成功添加索引

fail("commit:"+server.commit());

queryAll();

}catch(SolrServerExceptione){

e.printStackTrace();

}catch(IOExceptione){

e.printStackTrace();

}

}


11、文档查询

/**

*<b>function:</b>query基本用法测试

*@authorhoojo

*@createDate2011-10-20下午04:44:28

*/

@Test

publicvoidqueryCase(){

//AND并且

SolrQueryparams=newSolrQuery("name:appleANDmanu:inc");


//OR或者

params.setQuery("name:appleORmanu:apache");

//空格等同于OR

params.setQuery("name:servermanu:dell");


//params.setQuery("name:solr-manu:inc");

//params.setQuery("name:server+manu:dell");


//查询name包含solrapple

params.setQuery("name:solr,apple");

//manu不包含inc

params.setQuery("name:solr,appleNOTmanu:inc");


//50<=price<=200

params.setQuery("price:[50TO200]");

params.setQuery("popularity:[5TO6]");

//params.setQuery("price:[50TO200]-popularity:[5TO6]");

//params.setQuery("price:[50TO200]+popularity:[5TO6]");


//50<=price<=200AND5<=popularity<=6

params.setQuery("price:[50TO200]ANDpopularity:[5TO6]");

params.setQuery("price:[50TO200]ORpopularity:[5TO6]");


//过滤器查询,可以提高性能filter类似多个条件组合,如and

//params.addFilterQuery("id:VA902B");

//params.addFilterQuery("price:[50TO200]");

//params.addFilterQuery("popularity:[*TO5]");

//params.addFilterQuery("weight:*");

//0<popularity<6没有等于

//params.addFilterQuery("popularity:{0TO6}");


//排序

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("<fontcolor='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{

QueryResponseresponse=server.query(params);


/*List<Index>indexs=response.getBeans(Index.class);

for(inti=0;i<indexs.size();i++){

fail(indexs.get(i));

}*/


//输出查询结果集

SolrDocumentListlist=response.getResults();

fail("queryresultnums:"+list.getNumFound());

for(inti=0;i<list.size();i++){

fail(list.get(i));

}


//输出分片信息

List<FacetField>facets=response.getFacetFields();

for(FacetFieldfacet:facets){

fail(facet);

List<Count>facetCounts=facet.getValues();

for(FacetField.Countcount:facetCounts){

System.out.println(count.getName()+":"+count.getCount());

}

}

}catch(SolrServerExceptione){

e.printStackTrace();

}

}


12、分片查询、统计

/**

*<b>function:</b>分片查询,可以统计关键字及出现的次数、或是做自动补全提示

*@authorhoojo

*@createDate2011-10-20下午04:54:25

*/

@Test

publicvoidfacetQueryCase(){

SolrQueryparams=newSolrQuery("*:*");


//排序

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{

QueryResponseresponse=server.query(params);


//输出查询结果集

SolrDocumentListlist=response.getResults();

fail("Queryresultnums:"+list.getNumFound());


for(inti=0;i<list.size();i++){

fail(list.get(i));

}


fail("Allfacetfiledresult:");

//输出分片信息

List<FacetField>facets=response.getFacetFields();

for(FacetFieldfacet:facets){

fail(facet);

List<Count>facetCounts=facet.getValues();

for(FacetField.Countcount:facetCounts){

//关键字-出现次数

fail(count.getName()+":"+count.getCount());

}

}


fail("Searchfacet[name]filedresult:");

//输出分片信息

FacetFieldfacetField=response.getFacetField("name");

List<Count>facetFields=facetField.getValues();

for(Countcount:facetFields){

//关键字-出现次数

fail(count.getName()+":"+count.getCount());

}

}catch(SolrServerExceptione){

e.printStackTrace();

}

}


分片查询在某些统计关键字的时候还是很有用的,可以统计关键字出现的次数,可以通过统计的关键字来搜索相关文档的信息。


四、Document文档和JavaBean相互转换

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

packagecom.hoo.entity;


importjava.io.Serializable;

importorg.apache.solr.client.solrj.beans.Field;


/**

*<b>function:</b>UserEntityBean;所有被添加Annotation@Field注解的属性将参与index操作

*@authorhoojo

*@createDate2011-10-19下午04:16:00

*@fileUser.java

*@packagecom.hoo.entity

*@projectSolrExample

*@blog'target='_blank'>http://blog.csdn.net/IBM_hoojo[/code]
*@emailhoojo_@126.com

*@version1.0

*/

publicclassUserimplementsSerializable{


/**

*@authorHoojo

*/

privatestaticfinallongserialVersionUID=8606788203814942679L;


//@Field

privateintid;

@Field

privateStringname;

@Field

privateintage;


/**

*可以给某个属性重命名,likes就是solrindex的属性;在solrIndex中将显示like为likes

*/

@Field("likes")

privateString[]like;

@Field

privateStringaddress;

@Field

privateStringsex;

@Field

privateStringremark;

publicintgetId(){

returnid;

}


//setter方法上面也可以

@Field

publicvoidsetId(intid){

this.id=id;

}

publicStringgetName(){

returnname;

}

//getter、setter


@Override

publicStringtoString(){

returnthis.id+"#"+this.name+"#"+this.age+"#"+this.like+"#"+this.address+"#"+this.sex+"#"+this.remark;

}

}


测试类代码如下
packagecom.hoo.test;


importorg.apache.solr.client.solrj.beans.DocumentObjectBinder;

importorg.apache.solr.common.SolrDocument;

importorg.apache.solr.common.SolrDocumentList;

importorg.apache.solr.common.SolrInputDocument;

importorg.apache.solr.common.SolrInputField;

importorg.junit.Test;

importcom.hoo.entity.User;


/**

*<b>function:</b>SolrInputDocumentimplementsMap,Iterable

*@authorhoojo

*@createDate2011-10-19下午03:54:54

*@fileSolrInputDocumentTest.java

*@packagecom.hoo.test

*@projectSolrExample

*@blog'target='_blank'>http://blog.csdn.net/IBM_hoojo[/code]
*@emailhoojo_@126.com

*@version1.0

*/

publicclassSolrInputDocumentTest{


publicfinalvoidfail(Objecto){

System.out.println(o);

}


/**

*<b>function:</b>创建SolrInputDocument

*@authorhoojo

*@createDate2011-10-21下午03:38:20

*/

@Test

publicvoidcreateDoc(){

SolrInputDocumentdoc=newSolrInputDocument();

doc.addField("id",System.currentTimeMillis());

doc.addField("name","SolrInputDocument");

doc.addField("age",22,2.0f);


doc.addField("like",newString[]{"music","book","sport"});


doc.put("address",newSolrInputField("guangzhou"));


doc.setField("sex","man");

doc.setField("remark","chinapeople",2.0f);


fail(doc);

}


/**

*<b>function:</b>利用DocumentObjectBinder对象将SolrInputDocument和User对象相互转换

*@authorhoojo

*@createDate2011-10-21下午03:38:40

*/

@Test

publicvoiddocAndBean4Binder(){

SolrDocumentdoc=newSolrDocument();

doc.addField("id",456);

doc.addField("name","SolrInputDocument");


doc.addField("likes",newString[]{"music","book","sport"});


doc.put("address","guangzhou");


doc.setField("sex","man");

doc.setField("remark","chinapeople");


DocumentObjectBinderbinder=newDocumentObjectBinder();


Useruser=newUser();

user.setId(222);

user.setName("JavaBean");

user.setLike(newString[]{"music","book","sport"});

user.setAddress("guangdong");


fail(doc);

//User->>SolrInputDocument

fail(binder.toSolrInputDocument(user));

//SolrDocument->>User

fail(binder.getBean(User.class,doc));


SolrDocumentListlist=newSolrDocumentList();

list.add(doc);

list.add(doc);

//SolrDocumentList->>List

fail(binder.getBeans(User.class,list));

}


/**

*<b>function:</b>SolrInputDocument的相关方法

*@authorhoojo

*@createDate2011-10-21下午03:44:30

*/

@Test

publicvoiddocMethod(){

SolrInputDocumentdoc=newSolrInputDocument();

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());

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: