Apache Solr入门

朱风史
2023-12-01

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”现在将索引和命令提示符将显示以下输出。

现在我们导航到以下网址并选择核心。

http://localhost:8983/solr

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,不过这只是逻辑上的删除,并没有真正从索引中移除掉

  1. Solr的客户端API的

有不同的客户端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);  
 类似资料: