Apache Solr是一个功能强大的搜索服务器,它支持REST风格API。Solr是基于Lucene的,Lucene 支持强大的匹配能力,如短语,通配符,连接,分组和更多不同的数据类型。它使用 Apache Zookeeper特别针对高流量进行优化。Apache Solr提供各式各样的功能,我们列出了部分最主要的功能。
先进的全文搜索功能。
XML,JSON和HTTP - 基于开放接口标准。
高度可扩展和容错。
同时支持模式和无模式配置。
分页搜索和过滤。
支持像英语,德语,中国,日本,法国和许多主要语言
丰富的文档分析。
安装Apache Solr
下载solr链接:http://lucene.apache.org/solr/downloads.html
Solr的文件夹
bin文件夹中包含用来启动和停止服务器的脚本。example 文件夹包含几个示例文件。我们将使用其中的一种,以说明Solr如何索引数据。server 文件夹包含logs 文件夹,所有的Solr的日志都写入该文件夹。这将有助于索引过程来检查任何错误日志。在sever文件夹下的Solr文件夹包含不同的集合或核心(core/collection)。对于各集合或核心的配置和数据都存储在相应的集合或核心文件夹。
Apache Solr带有一个内置的Jetty服务器。但在我们开始之前,我们必须验证JAVA_HOME已经配置。
使用命令行脚本启动服务器。去solr的bin目录,从命令提示符输入出以下命令
solr start
这将启动下的默认端口8983 Solr的服务器。
现在,我们可以在浏览器中打开网址验证,我们的Solr的实例正在运行。Solr管理控制台:http://localhost:8983/Solr/
1.建立核心(core)
当Solr的服务器在独立模式下启动的配置称为核心,当它在SolrCloud模式启动的配置称为集合。在这个例子中,我们将有关独立服务器和核心讨论。我们将在以后再讨论SolrCloud。首先,我们需要创建一个核心的索引数据。Solr的创建命令有以下选项:
-c -要创建的核心或集合的名称(必需)。
-d -配置目录,在SolrCloud模式非常有用。
-n -配置名称。这将默认为核心或集合的名称。
-p -本地Solr的实例的端口发送create命令; 默认脚本试图通过寻找运行Solr的实例来检测端口。
-s -Number of shards to split a collection into, default is 1.
-rf -集合中的每个文件的份数。默认值是1。
在这个例子中,我们将使用的核心名称和配置目录-d参数-c参数。对于所有其它参数我们使用默认设置。
在命令窗口浏览 solr-6.3.0\bin文件夹,并发出以下命令。
建立核心liu:solr create -c liu-d basic_configs
2.修改Schema.xml文件(6.3版本改managed-schema文件)
server\solr\liu\conf需要修改schema.xml中文件。我们将使用随Solr的安装索引附带的solr-6.3.0\example\exampledocs下的示例文件“books.json”。
现在,我们定位到该文件夹 server\solr目录。你会看到一个名为liu的文件夹被创建。子文件夹conf和data分别拥有核心的配置和索引的数据。
现在编辑D:\solr-6.3.0\server\solr\liu\conf\managed-schema文件,添加以下内容。
<uniqueKey>id</uniqueKey>
<field name="cat" type="text_general" indexed="true" stored="true"/>
<field name="name" type="text_general" indexed="true" stored="true"/>
<field name="price" type="tdouble" indexed="true" stored="true"/>
<field name="inStock" type="boolean" indexed="true" stored="true"/>
<field name="author" type="text_general" indexed="true" stored="true"/>
我们已经设置了属性索引为true。这指定字段用于索引和记录可以使用索引进行检索。该值设置为false将只存储领域,但不能进行查询。
另外请注意另一个属性stored并将其设置为true。这指定字段被存储,并且可以在输出被返回。将此字段设置为false将使字段唯一索引,并且不能在输出进行检索。
我们已经分配给存在于此处的“books.json”文件中的字段的类型。在json文件“ID”第一场由索引Schema.xml文件的唯一键自动元素的照顾。如果你注意,我们已经略过字段series_t,sequence_i和genre_s未做任何条目。但是,当我们执行索引时,所有这些字段都被索引且没有任何问题。如果你想知道这种情况需要在Schema.xml文件的dynamicField部分一探究竟。
再介绍一下索引字段参数的含义:
属性 描述
name 字段类型名
class java类名
indexed 默认true。 说明这个数据应被搜索和排序,如果数据没有indexed,则stored应是。
stored 默认。说明这个字段被包含在搜索结果中是合适的。如果数据没有stored,则indexed应是。
omitNorms 字段的长度不影响得分和在索引时不做boost时,设置它为。一般文本字段不设置为。
termVectors 如果字段被用来做more like this 和highlight的特性时应设置为。
compressed 字段为压缩的,这也许会导致索引跟搜索速度变慢,不过可以减少存储空间,只有StrField和TextField是可以压缩,适合字段的长度大于200个字符。
multiValued 字段多于一个值的时候,可设置为true。
来源: http://www.daixiaorui.com/read/144.html
既然已经修改了配置,我们必须停止和启动服务器。通过命令行bin目录。
Solr stop -all
服务器将停止现在。现在启动服务器问题从bin目录中通过命令行运行以下命令。
Solr start
3.索引数据
Apache Solr带有一个叫做SimplePostTool独立的Java程序。这个程序被打包成JAR,在安装目录下 example\exampledocs可看到。
现在,我们在命令行定位到example\exampledocs文件夹,然后键入以下命令。你会看到一堆选项,使用的工具。
Java -jar post.jar -h
在一般的使用格式如下用途:
Usage: java [SystemProperties] -jar post.jar [-h|-] [<file|folder|url|arg>
[<file|folder|url|arg>…]]
正如我们前面所说,我们将索引“books.json”文件中的数据。我们将导航到solr-6.3.0\example\exampledocs在命令提示符并发出以下命令。
java -Dtype=application/json -Dc=liu -jar post.jar books.json
这里使用的SystemProperties是:
-dtype - 数据文件的类型。
-Dc - 核心的目录。
文件“books.json”现在将索引和命令提示符将显示以下输出。
现在我们导航到以下网址并选择核心。
4.访问索引的文档
Apache Solr提供了一种基于REST API来访问的数据,并还提供了不同的参数,以检索数据。我们将向您展示一些基于场景的查询。
基本查询
q – 查询字符串,必须的。
fl – 指定返回那些字段内容,用逗号或空格分隔多个。
start – 返回第一条记录在完整找到结果中的偏移位置,0开始,一般分页用。
rows – 指定返回结果最多有多少条记录,配合start来实现分页。
sort – 排序,格式:sort=+<desc|asc>[,+<desc|asc>]… 。示例:(inStock desc, price asc)表示先 “inStock” 降序, 再 “price” 升序,默认是相关性降序。
wt – (writer type)指定输出格式,可以有 xml, json, php, phps, 后面 solr 1.3增加的,要用通知我们,因为默认没有打开。
fq – (filter query)过虑查询,作用:在q查询符合结果中同时是fq查询符合的,例如:q=mm&fq=date_time:[20081001 TO 20091031],找关键字mm,并且date_time是20081001到20091031之间的。
qt – (query type)指定那个类型来处理查询请求,一般不用指定,默认是standard。
[Solr的检索运算符]
“:” 指定字段查指定值,如返回所有值*?
“?”表示单个任意字符的通配
“” 表示多个任意字符的通配(不能在检索的项开始使用或者?符号)
“”表示模糊检索,如检索拼写类似于”roam”的项这样写:roam将找到形如foam和roams的单词;roam~0.8,检索返回相似度在0.8以上的记录。
²邻近检索,如检索相隔10个单词的”apache”和”jakarta”,”jakarta apache”~10
“^”控制相关度检索,如检索jakarta apache,同时希望去让”jakarta”的相关度更加好,那么在其后加上””符号和增量值,即jakarta4 apache
布尔操作符AND、||
布尔操作符OR、&&
布尔操作符NOT、!、-(排除操作符不能单独与项使用构成查询)
“+” 存在操作符,要求符号”+”后的项必须在文档相应的域中存在
( ) 用于构成子查询
[] 包含范围检索,如检索某时间段记录,包含头尾,date:[200707 TO 200710]
{}不包含范围检索,如检索某时间段记录,不包含头尾
date:{200707 TO 200710}
” 转义操作符,特殊字符包括+ – & | ! ( ) { } [ ] ^ ” ~ * ? : “
来源: http://haiziwoainixx.iteye.com/blog/2095599
搜索使用的条件
Solr的支持条件的搜索。我们可以设置条件,我们的查询提供了“FQ”参数。在下面我们将告诉你如何查询价格低于¥6的书。
http://localhost:8983/solr/liu/select?q=*&fq=price:[0 TO 6]
输出将只列出这是低于$ 6的书籍
更新数据
如果同一份文档solr.xml重复导入会出现什么情况呢?实际上solr会根据文档的字段id来唯一标识文档,如果导入的文档的id已经存在solr中,那么这份文档就被最新导入的同id的文档自动替换。你可以自己尝试试验一下,观察替换前后管理界面的几个参数:Num Docs,Max Doc,Deleted Docs的变化。
numDocs:当前系统中的文档数量,它有可能大于xml文件个数,因为一个xml文件可能有多个标签。
maxDoc:maxDoc有可能比numDocs的值要大,比如重复post同一份文件后,maxDoc值就增大了。
deletedDocs:重复post的文件会替换掉老的文档,同时deltedDocs的值也会加1,不过这只是逻辑上的删除,并没有真正从索引中移除掉
有不同的客户端API的可用来连接到Solr的服务器。我们列出了一些广泛使用的Solr客户端API的。
SolRuby – To connect from Ruby
SolPHP – To connect from PHP
PySolr – To connect from Python
SolPerl – To connect from Perl
SolrJ – To connect from Java
SolrSharp – To connect from C#
此外,Solr还提供了JavaScript可以直接使用的基于REST的API。
6.SolrJ的使用
1.maven依赖:
<!-- solrj -->
<dependency>
<groupId>org.apache.solr</groupId>
<artifactId>solr-solrj</artifactId>
<version>6.3.0</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.7</version>
</dependency>
2.实体类(Student.java),重点是@Field注解不能少,否则会出现org.apache.solr.client.solrj.beans.BindingException: …does not define any fields.异常
@Field("id")
private String id;
@Field
private String firstName;
@Field
private String lastName;
记得去配managed-schema文件或者schema.xml
3.代码概要(详情见附件SolrDao.java和测试类SolrTest.java)
String DEFAULT_URL = “http://localhost:8983/solr/liu”;
SolrClient solrClient = new HttpSolrClient.Builder(DEFAULT_URL).build();
/**
* 保存单个对象
* @param object
* @return
*/
public Boolean saveOrUpdate(Object object) {
try {
updateResponse = solrClient.addBean(object);
solrClient.commit();
if (updateResponse.getStatus() == 0) {
return Boolean.valueOf(true);
}
} catch (SolrServerException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return Boolean.valueOf(false);
}
/**
* 保存多个对象
* @param objects
* @return
*/
public Boolean saveOrUpdates(Collection objects) {
try {
updateResponse = solrClient.addBeans(objects.iterator());
solrClient.optimize();
solrClient.commit();
if (updateResponse.getStatus() == 0) {
return Boolean.valueOf(true);
}
} catch (SolrServerException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return Boolean.valueOf(false);
}
/**
* 删除索引
* @param id
* @return
*/
public Boolean remove(String id) {
try {
updateResponse = solrClient.deleteById(id);
solrClient.commit();
if (updateResponse.getStatus() == 0) {
return true;
}
} catch (SolrServerException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
/**
* 查询
* @param q
* @return
* @throws IOException
*/
@SuppressWarnings("unchecked")
public List<Object> query(String q) {
ModifiableSolrParams params = new ModifiableSolrParams();
params.set("q", q);
params.set("start", getStart().intValue());
params.set("rows", getRows().intValue());
if (getSort() != null) {
params.set("sort", new String[] { getSort() });
}
params.set("fl", new String[] { getFl() });
params.set("fq", getFq());
List<Object> result = new ArrayList<Object>();
try {
queryResponse = solrClient.query(params);
SolrDocumentList list = queryResponse.getResults();
DocumentObjectBinder binder = new DocumentObjectBinder();
result = binder.getBeans(entityClass, list);
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
========================
测试:
SolrDao solrDao = new SolrDao(Student.class);
//测试增加索引
Student student1 = new Student("1","1", "勇");
Student student2 = new Student("2","2", "勇");
List<Student> list = new ArrayList<>();
list.add(student1);
list.add(student2);
System.out.println(solrDao.saveOrUpdates(list));
//测试删除索引
System.out.println(solrDao.remove("1"));
//测试查询
solrDao.setFq(new String[]{"id:206","name:刘"}); //过滤查询
List<Object> results = solrDao.query("*:*"); //
System.out.println(results);