前言
为什么要引入Solr,它到底有什么优势。假想有这样一种情况,当我们在oracle去查询一些东西,无非是使用like或者join(当查询条件多,涉及的多表的话)这几种操作。当数据量大的时候,很难相信在大型数据库上去执行高速的查询,有以下两点原因:一是,数据库本身在性能上缺乏亮点,所以我们总提性能。二是,松散的文本,查询的话基本都是基于like,而join和like是数据库的性能杀手,与最求高效快速的理念相违背。所以我们需要一种和sql完全不同的数据检索方式,由此引出了solr。
1. 安装部署
1.1 官方定义
Solr是一个独立的企业级搜索应用服务器,它对外提供类似于Web-service的API接口。用户可以通过http请求,向搜索引擎服务器提交一定格式的XML文件,生成索引;也可以通过Http Get操作提出查找请求,并得到XML格式的返回结果。
Solr是一个基于Lucene的Java搜索引擎服务器。Solr 提供了层面搜索、命中醒目显示并且支持多种输出格式(包括 XML/XSLT 和 JSON 格式)。它易于安装和配置,而且附带了一个基于 HTTP 的管理界面。Solr已经在众多大型的网站中使用,较为成熟和稳定。Solr 包装并扩展了 Lucene,所以Solr的基本上沿用了Lucene的相关术语。更重要的是,Solr 创建的索引与 Lucene 搜索引擎库完全兼容。通过对Solr 进行适当的配置,某些情况下可能需要进行编码,Solr 可以阅读和使用构建到其他 Lucene 应用程序中的索引。此外,很多 Lucene 工具(如Nutch、 Luke)也可以使用Solr 创建的索引。
简单来说:solr就是一个开源的搜索引擎框架。
1.2 原理
Solr对外提供标准的http接口来实现对数据的索引的增加、删除、查询。在 Solr 中,用户通过向部署在servlet 容器中的 Solr Web 应用程序发送 HTTP 请求来启动索引和搜索。Solr 接受请求,确定要使用的适当SolrRequestHandler,然后处理请求。通过 HTTP 以同样的方式返回响应。默认配置返回Solr 的标准 XML 响应,也可以配置Solr 的备用响应格式。
可以向 Solr 索引 servlet 传递四个不同的索引请求:
add/update 允许向 Solr 添加文档或更新文档。直到提交后才能搜索到这些添加和更新。
commit 告诉 Solr,提交后就可以搜索到。
optimize 重构 Lucene 的文件以改进搜索性能。索引完成后执行一下优化通常比较好。如果更新比较频繁,则应该在使用率较低的时候安排优化。一个索引无需优化也可以正常地运行。优化是一个耗时较多的过程。(官方:执行明确的优化,导致所有段的合并到一个。)
delete 可以通过 id 或查询来指定。按 id 删除将删除具有指定 id 的文档;按查询删除将删除查询返回的所有文档。
也就是说:solr可以对数据进行增加、删除、查询。
1.3 搭建solr
解压solr-7.7.3,打开解压的目录:
bin:Solr的脚本启动工具目录。
contrib:放关于solr的扩展。
dist:在这里能找到Solr的核心JAR包和扩展JAR包。当我们试图把Solr嵌入到某个应用程序的时候会用到核心JAR包。
distàsolrj-lib:包含构建基于Solr的客户端时会用到的JAR包。
distàtest-framework:包含测试Solr时候会用到的JAR包。
docs:该文件夹里面存放的是Solr文档,离线的静态HTML文件,还有API的描述。
example:包含Solr的简单示例。
licenses:各种许可和协。
server:在本地把Solr作为服务运行的必要文件都存放在这里。
1.4 部署属于自己的solr
a) 下载solr7.7.3 https://mirrors.bfsu.edu.cn/apache/lucene/solr/7.7.3/solr-7.7.3.tgz
b) 解压缩下载下来的的官方压缩包,里面(包含jetty与solr项目),解压缩后是一整个文件,别把里面的内容分开
c) 进入解压缩后的文件下的bin目录
d) 使用命令 ./solr start启动solr
e)
2. 创建core
1. 直接在/solr-7.7.3/server/solr
下创建新文件夹,自定义文件夹名称作为新的an-core
。将/server/solr/configsets/_default
目录下的conf文件夹,然后拷贝一份至an-core
文件夹目录。
2. 打开Solr面板,添加新创建的an-core
的Solr Core。
Solr面板
基础面板
- Dashboard: 仪表盘,显示了该Solr实例开始启动运行的时间、版本、系统资源、jvm等信息。
- Logging: Solr运行日志信息。
- Cloud:Cloud即SolrCloud,即Solr云(集群),当使用Solr Cloud模式运行时会显示此菜单。
- Core Admin:Solr Core的管理界面,在这里可以添加SolrCore实例。
- Java Properties:Solr在JVM 运行环境中的属性信息,包括类路径、文件编码、jvm内存设置等信息。
- Tread Dump:显示Solr Server中当前活跃线程信息,同时也可以跟踪线程运行栈信息。
- Core Selector:选择一个SolrCore进行详细操作。
Core Selector
- Analysis:通过Analysis界面可以测试索引分析器和搜索分析器的执行情况。在Solr中,分析器是绑定在域的类型中的。
- Dataimport可以定义数据导入处理器,从关系数据库将数据导入到Solr索引库中。默认没有配置,需要手工配置。
- Documents:通过/update表示更新索引,Solr默认根据id(唯一约束)域来更新Document的内容,如果根据id值搜索不到id域则会执行添加操作,如果找到则更新。通过此菜单可以创建索引、更新索引、删除索引等操作。
- Query:通过/select执行搜索索引,必须指定“q”查询条件方可搜索。
managed-schema
field
<field name="id" type="string" indexed="true" stored="true" required="true" multiValued="false" />
Field节点指定建立索引和查询数据的字段。
- name:指定域的名称
- type:指定域的类型
- indexed:是否索引
- stored:是否存储
- required:是否必须
- multiValued:是否多值,比如商品信息中,一个商品有多张图片,一个Field想存储多个值的话,必须将multiValued设置为true
dynamicField
<dynamicField name="*_i" type="pint" indexed="true" stored="true"/>
dynamicField 表示动态字段,可以动态定义一个字段,只要符合规则的字段都可以。
- name:指定动态域的命名规则,*_i只要以_i结尾的字段都满足这个定义。
- type:指定域的类型
- indexed:是否索引
- stored:是否存储
uniqueKey
<uniqueKey>id</uniqueKey>
指定唯一键。其中的id是在Field标签中已经定义好的域名,而且该域要设置为required为true。 一个managed-schema文件中必须有且仅有一个唯一键。
copyField
<copyField source="cat" dest="_text_"/>
通过copyField,可以把一个字段的值复制到另一个字段中,也可以把多个字段的值同时复制到另一个字段中,这样搜索的时候都可以根据一个字段来进行搜索。
- source:要复制的源Field域的域名
- dest:目标Field域的域名
由dest指的的目标Field域,必须设置multiValued为true。fieldType
<fieldType name="text_general" class="solr.TextField" positionIncrementGap="100"> <analyzer type="index"> <tokenizer class="solr.StandardTokenizerFactory"/> <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt" /> <filter class="solr.LowerCaseFilterFactory"/> </analyzer> <analyzer type="query"> <tokenizer class="solr.StandardTokenizerFactory"/> <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt" /> <filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/> <filter class="solr.LowerCaseFilterFactory"/> </analyzer> </fieldType>
fieldType节点主要用来定义域的类型。
- name:指定域类型的名称
- class:指定该域类型对应的solr的类型
- analyzer:指定分析器
- type:index、query,分别指定搜索和索引时的分析器
- tokenizer:指定分词器
- filter:指定过滤器
- positionIncrementGap:可选属性,定义在同一个文档中此类型数据的空白间隔,避免短语匹配错误
solrconfig.xml
datadir
<dataDir>${solr.data.dir:}</dataDir>
每个SolrCore都有自己的索引文件目录 ,默认在SolrCore目录下的data中。
luceneMatchVersion
<luceneMatchVersion>7.4.0</luceneMatchVersion>
表示solr底层使用的是Lucene7.4.0版本
lib
<lib dir="${solr.install.dir:../../../..}/contrib/extraction/lib" regex=".*\.jar" />
表示Solr引用包的位置,当dir对应的目录不存在时候,会忽略此属性。
solr.install.dir:
表示solrcore的安装目录。requestHandler
<requestHandler name="/query" class="solr.SearchHandler"> <lst name="defaults"> <str name="echoParams">explicit</str> <str name="wt">json</str> <str name="indent">true</str> </lst> </requestHandler> 1234567
requestHandler请求处理器,定义了索引和搜索的访问方式。 通过/update维护索引,可以完成索引的添加、修改、删除操作;通过/select搜索索引。
设置搜索参数完成搜索,搜索参数也可以设置一些默认值,如下
<directoryFactory name="DirectoryFactory" class="${solr.directoryFactory:solr.NRTCachingDirectoryFactory}"/>
定义索引的存储方案,共有以下存储方案:
- solr.StandardDirectoryFactory——这是一个基于文件系统存储目录的工厂,它会试图选择最好的实现基于你当前的操作系统和Java虚拟机版本。
- solr.SimpleFSDirectoryFactory——适用于小型应用程序,不支持大数据和多线程。
- solr.NIOFSDirectoryFactory——适用于多线程环境,但是不适用在windows平台(很慢),是因为JVM还存在bug。
- solr.MMapDirectoryFactory——这个是solr3.1到4.0版本在linux64位系统下默认的实现。它是通过使用虚拟内存和内核特性调用mmap去访问存储在磁盘中的索引文件。它允许lucene或solr直接访问I/O缓存。如果不需要近实时搜索功能,使用此工厂是个不错的方案。
- solr.NRTCachingDirectoryFactory——此工厂设计目的是存储部分索引在内存中,从而加快了近实时搜索的速度。
- solr.RAMDirectoryFactory——这是一个内存存储方案,不能持久化存储,在系统重启或服务器crash时数据会丢失。且不支持索引复制。
3. 安装中文分词器
配置smartcn中文分词器
solr安装包有提供Smartcn中文分词架包,在
\solr-7.7.3\contrib\analysis-extras\lucene-libs
下,我这里使用solr 7.7,所以架包名称为lucene-analyzers-smartcn-7.7.3.jar
-
把smartcn中文分词器架包复制到solr项目的WEB-INF/lib目录下
-
找到solrhome/${collection}/conf/managed-schema
添加smartch中文分词器配置
<schema>
<!-- 配置中文分词器 -->
<fieldType name="text_zh" class="solr.TextField" positionIncrementGap="100">
<analyzer type="index">
<tokenizer class="org.apache.lucene.analysis.cn.smart.HMMChineseTokenizerFactory"/>
</analyzer>
<analyzer type="query">
<tokenizer class="org.apache.lucene.analysis.cn.smart.HMMChineseTokenizerFactory"/>
</analyzer>
</fieldType>
</schema>
重启solr 查看结果
配置IK Analyzer中文分词器
- 先下载 IK Analyzer中文分词器架包及相关配置文件。
- 将ik的相关文件 拷贝到 webapps\solr\WEB-INF\lib 目录下
- 在 solr_home\mycore1\conf\schema.xml 增加如下配置
<!-- 我添加的IK分词 -->
<fieldType name="text_ik" class="solr.TextField">
<analyzer type="index" isMaxWordLength="false" class="org.wltea.analyzer.lucene.IKAnalyzer"/>
<analyzer type="query" isMaxWordLength="true" class="org.wltea.analyzer.lucene.IKAnalyzer"/>
</fieldType>
4. DIH导入索引数据
DIH简介:
DIH全称是Data Import Handler 数据导入处理器,顾名思义这是向solr中导入数据的,我们的solr目的就是为了能让我们的应用程序更快的查询出用户想要的数据,而数据存储在应用中的各种地方入xml、pdf、关系数据库中,那么solr首先就要能够获取这些数据并在这些数据中建立索引来达成快速搜索的目的,这里就列举我们最常用的从关系型数据库中向solr导入索引数据。
在我们自己建立的core的目录下有conf目录,这里面有着几个很重要的配置文件,之前我们用到的managed-schema(老版本是schema.xml)也在其中,另外还有一个data-config.xml文件,这是我们DIH配置的第一步,需要在此文件中配置数据导入文件的映射位置如下图:
<requestHandler name="/dataimport" class="solr.DataImportHandler" >
<lst name="defaults">
<str name="config">data-config.xml</str>
</lst>
</requestHandler>
第二步配置数据导入文件,这个文件可以在solr根目录下的示例文件中copy一份到core/conf目录下,也就是跟solrconfig.xml在一个目录下,因为solrconfig.xml中配置的相对路径就是这里,当然也可以写绝对路径。如下图:
Copy过去之后这个文件名可以自定义,我就改成了data-config.xml,下面开始配置如下图:
重要!!!在solr-7.7.3\dist中把solr-dataimporthandler-7.7.3.jar 复制到solr-7.7.3\server\solr-webapp\webapp\WEB-INF\lib下
(1)首先配置数据源关系型数据库基本四项,驱动类,url,用户名,密码。
(2)配置document,可以把它当作与mysql中数据库一个层级的对象。
(3)配置entity,可以把它当作与数据库中一个表对应,在query中书写查询sql。
(4)配置field与表中的字段与之对应。
注意这里容易与schema中的配置混淆,我的理解是schema中配置的是创建索引的配置,而索引的创建需要有数据基础,而现在讲的数据导入文件就是建立索引的数据基础,他是创建索引的元数据。现在配置文件完成后可以用DIH命令执行了。
在managed-schema去添加字段类型和名称(author和name配置文件中有,修改一下type即可,id配置文件中也有)
<field name="INFO_NAME" type="string" indexed="true" stored="true"/>
验证成果
重启solr,打开Solr的Dataimport面板;选择entity,点击Execute执行。
接下来验证下数据是否真的导入成功了,如下图
fq:过滤的字段,df:默认查询字段,start,rows:分页配置,sort:排序,更多关于查询语句的介绍请参考http://lucene.apache.org/solr/guide/7_4/searching.html
六、solrJ(java客户端)
简介:solrJ是java访问solr的客户端工具包,solr也提供了其他语言访问的客户端,可以到官方文档查看,现在solr的索引和数据导入都已经有,但是作为项目中应用的一个组件,少不了java与solr的沟通。
5. JavaApi调用solr
-
导入相关的MAVEN依赖
-
<dependency> <groupId>org.apache.solr</groupId> <artifactId>solr-solrj</artifactId> <version>7.7.0</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency>
-
书写实体类(注意:实体类必须添加无参有参构造函数 和 get set注解)
import org.apache.solr.client.solrj.beans.Field;
public class Demo {
@Field("id")
private String id;
@Field("INFO_NAME")
private String infoName;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getInfoName() {
return infoName;
}
public void setInfoName(String infoName) {
this.infoName = infoName;
}
public Demo(String id, String infoName) {
this.id = id;
this.infoName = infoName;
}
public Demo() {
}
@Override
public String toString() {
return "Demo{" +
"id='" + id + '\'' +
", infoName='" + infoName + '\'' +
'}';
}
}
-
调用solr查询
-
import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.SolrQuery; import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.client.solrj.impl.HttpSolrClient; import org.apache.solr.client.solrj.response.QueryResponse; import java.io.IOException; import java.util.List; public class TestSolr { public static void main(String[] args) throws IOException, SolrServerException { SolrClient solrClient = new HttpSolrClient.Builder("http://localhost:8983/solr/").build(); SolrQuery params = new SolrQuery(); params.set("q", "*:*"); // String search = "*:*"; // params.setQuery(search); //每页记录数(默认10) params.setRows(1000); QueryResponse query = solrClient.query("an-core", params); List<Demo> beans = query.getBeans(Demo.class); System.out.println(beans); System.out.println(query); } }
感谢各个博主资料的支持,整理文档参考资料网址较多,如有遗漏联系补全
资料参考网址:https://www.cnblogs.com/xiao-zhang-blogs/p/7339476.html