solrj的使用
solrj是一个java客户端访问solr,它定义了一个java接口来添加、修改、查询solr的索引。本页描述的solrj使用Solr释放包括1.4 x版本,
solrj/solr兼容性
solrj一般保持向后兼容性,你可以使用一个新的solrj调用旧的solr,或一个老solrj调用新的solr。这里有一些小的例外情况:
如果你把1。x和以后的版本,你必须设置响应解析器,XML,因为这两个版本使用javabin不兼容的版本。
server.setParser(new XMLResponseParser());
混合3。x 和4。x或之后的版本工作正常,只要你没有改变请求writer二进制。这是关于改变默认请求writer二进制solr-3038讨论。如果这样做了,然后之间的兼容性3。x和以后的版本将需要设置请求writer明确的XML版本。如果更改了,还有另一个讨论solr-4820加设自动交通检测。
这是一个javabin形式例外,这改变了主要版本间不兼容的方式。你不能在1.4.1以上和3.1或更高版本之间使用javabin之间的沟通
设置classpath
Solrj使用有几个文件夹需要包含, /dist, /dist/solrj-lib 和 /lib,最小的一组jar(你会发现这取决于你的使用场景别人需要)使用solrj如下:
From /dist:
- apache-solr-solrj-*.jar
From /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
From /lib
- slf4j-jdk14-1.5.5.jar
Maven
Solrj支持使用 Maven repository,使用下面的文件添加到你的pom.xml,使用solrj
<dependency>
<artifactId>solr-solrj</artifactId>
<groupId>org.apache.solr</groupId>
<version>1.4.0</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
如果你使用EmbeddedSolrServer,你也需要添加solr-core的依赖。
<dependency>
<artifactId>solr-core</artifactId>
<groupId>org.apache.solr</groupId>
<version>1.4.0</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
当然,如果使用EmbeddedSolrServer,确保solr依赖了Servlet API,这可能已经在您的基于Web的应用程序中存在了,但是使用命令行需要依赖像这样:
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
</dependency>
如果出现异常NoClassDefFoundError,需要包含下面的jar文件。
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.5.6</version>
</dependency>
如果你使用的solr-solrj version 1.4.1 且slf4j-simple 1.5.6,你可能会获得IllegalAccessError异常,因为slf4j-api已经发生了变化。Solrj使用的slf4j-api 1.5.5,所以你必须使用slf4j-simple 1.5或其他结合适当的版本
HttpSolrServer
HttpSolrServer使用的apache的Common Http Client链接solr,说明,在solr4.0以后,CommonsHttpSolrServer改变为HttpSolrServer,并且StreamingUpdateSolrServer 改变为ConcurrentUpdateSolrServer。
String url = "http://localhost:8983/solr";
/*
HttpSolrServer is thread-safe and if you are using the following constructor,
you *MUST* re-use the same instance for all requests. If instances are created on
the fly, it can cause a connection leak. The recommended practice is to keep a
static instance of HttpSolrServer per solr server url and share it for all requests.
See https://issues.apache.org/jira/browse/SOLR-861 for more details
*/
SolrServer server = new HttpSolrServer( url );
改变连接设置
HttpSolrServer也允许设置连接属性。
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
// Setting the XML response parser is only required for cross
// version compatibility and only when one side is 1.4.1 or
// earlier and the other side is 3.1 or later.
server.setParser(new XMLResponseParser()); // binary parser is used by default
// The following settings are provided here for completeness.
// They will not normally be required, and should only be used
// after consulting javadocs to know whether they are truly required.
server.setSoTimeout(1000); // socket read timeout
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);
EmbeddedSolrServer
EmbeddedSolrServer提供了相同的接口,而不是必须是一个HTTP请求。
// Note that the following property could be set through JVM level arguments too
System.setProperty("solr.solr.home", "/home/shalinsmangar/work/oss/branch-1.3/example/solr");
CoreContainer.Initializer initializer = new CoreContainer.Initializer();
CoreContainer coreContainer = initializer.initialize();
EmbeddedSolrServer server = new EmbeddedSolrServer(coreContainer, "");
如果你想使用MultiCore的特性,你应该向下面一样使用
File home = new File( "/path/to/solr/home" );
File f = new File( home, "solr.xml" );
CoreContainer container = new CoreContainer();
container.load( "/path/to/solr/home", f );
EmbeddedSolrServer server = new EmbeddedSolrServer( container, "core name as defined in solr.xml" );
...
如果你需要在一个嵌入式应用使用Solr,这是推荐的方法。你也可以与你是否有相同的接口访问HTTP工作。
说明:EmbeddedSolrServer 只能在solrconfig.xml.中注册,
用法
solrj被设计为一个可扩展的框架,通过solrrequest到solrserver并返回一个solrresponse。
为简单起见,最常见的命令是在solrserver建模:
向solr添加数据
首先获取一个server 的实例,使用HttpSolrServer.
SolrServer server = new HttpSolrServer("http://HOST:8983/solr/");
使用本地链接创建一个实例,嵌入式服务器:
SolrServer server = new EmbeddedSolrServer();
如果你想从索引中删除所有的数据,使用下面的方法
server.deleteByQuery( "*:*" );// CAUTION: deletes everything!
创建一个document
SolrInputDocument doc1 = new SolrInputDocument();
doc1.addField( "id", "id1", 1.0f );
doc1.addField( "name", "doc1", 1.0f );
doc1.addField( "price", 10 );
构造另外一个document。每个document可以单独添加更有效的做一个批处理更新。
SolrInputDocument doc2 = new SolrInputDocument();
doc2.addField( "id", "id2", 1.0f );
doc2.addField( "name", "doc2", 1.0f );
doc2.addField( "price", 20 );
字段id,name,price被添加到solr中中,因此你需要在SchemaXml.中自定义配置。
使用documents创建一个collections
Collection<SolrInputDocument> docs = new ArrayList<SolrInputDocument>();
docs.add( doc1 );
docs.add( doc2 );
将dcouemnt添加到 solr
server.add( docs );
提交
server.commit();
立即提交后添加文件,你可以使用:
UpdateRequest req = new UpdateRequest();
req.setAction( UpdateRequest.ACTION.COMMIT, false, false );
req.add( docs );
UpdateResponse rsp = req.process( server );
document流的更新
在大多数情况下concurrentupdatesolrserver会满足你的需要。另外,下面介绍的方法可以应用。
这是一个HTTP请求更新所有你的文档的最佳方法。
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加入POJO
通过注解创建一个java bean, “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;
}
“field注解适用于setter方法及实例:
@Field("cat")
public void setCategory(String[] c){
this.categories = c;
}
应该有相应的getter方法(没有注释)读取属性
SolrServer server = getSolrServer();
创建一个bean实例
Item item = new Item();
item.id = "one";
item.categories = new String[] { "aaa", "bbb", "ccc" };
server.addBean(item);
添加多个bean在一起
List<Item> beans ;
//add Item objects to the list
server.addBeans(beans);
说明——重用solrserver实例如果您使用此功能(性能)
Solr的事物
solr实现了在服务器级别事务。这意味着,每次提交或回滚,优化,适用于所有请求自上次提交/优化/回滚。
更新SOLR最合适的方法是一个过程,以避免竞争条件时使用的提交和回滚。同时,在理想情况下,应用程序将使用批处理自提交和优化可以是昂贵的例程。
从数据库读取数据
这个solrj例子尚未经过测试,
它会测试最终更新这里如果有问题。方法采用JDBC ResultSet的addresultset添加文件,Solr分批。管理数据库连接构建查询不包含在这里。
这是写的数据库字段名称在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;
}
}
设置RequestWriter
Solrj允许你上传 XML和二进制格式的内容。默认的是XML,使用下面的上传使用二进制格式。这是相同的格式,solrj采用批量提交,可以大大提高性能,减少了XML编组的开销。
server.setRequestWriter(new BinaryRequestWriter());
说明:请确定你在solrconfig.xml中配置了"BinaryUpdateRequestHandler",向下面一样
<requestHandler name="/update/javabin" class="solr.BinaryUpdateRequestHandler" />
通过solr读取数据
SolrServer server = getSolrServer();
SolrQuery query = new SolrQuery();
query.setQuery( "*:*" );
query.addSortField( "price", SolrQuery.ORDER.asc );
QueryResponse rsp = server.query( query );
SolrDocumentList docs = rsp.getResults();
使用注解的方式
List<Item> beans = rsp.getBeans(Item.class);
高级用法
solrj提供API来创建代替手工编码的查询。以下是一个faceted查询实例。
SolrServer server = getSolrServer();
SolrQuery solrQuery = new SolrQuery().
setQuery("ipod").
setFacet(true).
setFacetMinCount(1).
setFacetLimit(8).
addFacetField("category").
addFacetField("inStock");
QueryResponse rsp = server.query(solrQuery);
所有的add/setter方法返回自己的实例。因此,这些请求都可以链接
高亮
高亮像其他的普通的参数一样
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。
使用Groovy和 Grape
@Grab(group='org.apache.solr', module='solr-solrj', version='1.4.1')
@Grab(group='org.slf4j', module='slf4j-jdk14', version='1.5.5')
import org.apache.solr.client.solrj.impl.HttpSolrServer
import org.apache.solr.common.SolrInputDocument
String url = "http://localhost:8983/solr"
def server = new HttpSolrServer( url );
def doc = new SolrInputDocument()
doc.addField("id", 2)
doc.addField("word_s", "Cow")
doc.addField("desc_t", "Farm Animal")
server.add(doc)
server.commit()
println 'done'
使用SolrCloud
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();