一、介绍
企业站内搜索技术选型
在一些大型门户网站、电子商务网站等都需要站内搜索功能,使用传统的数据库查询方式实现搜索无法满足一些高级的搜索需求,比如:搜索速度要快、搜索结果按相关度排序、搜索内容格式不固定等,这里就需要使用全文检索技术实现搜索功能。
1. 单独使用Lucene实现
单独使用Lucene实现站内搜索需要开发的工作量较大,主要表现在:索引维护、索引性能优化、搜索性能优化等,因此不建议采用。
2. 使用Google或Baidu接口
通过第三方搜索引擎提供的接口实现站内搜索,这样和第三方引擎系统依赖紧密,不方便扩展,不建议采用。
3. 使用Solr实现
基于Solr实现站内搜索扩展性较好并且可以减少程序员的工作量,因为Solr提供了较为完备的搜索引擎解决方案,因此在门户、论坛等系统中常用此方案。
什么是Solr
Solr 是Apache下的一个顶级开源项目,采用Java开发,它是基于Lucene
的全文搜索服务器。Solr提供了比Lucene更为丰富的查询语言,同时实现了可配置、可扩展,并对索引、搜索性能进行了优化
Solr可以独立运行,运行在 Jetty、Tomcat 等这些 Servlet 容器中,Solr 索引的实现方法很简单,用 POST 方法向 Solr 服务器发送一个描述 Field 及其内容的 XML 文档,Solr根据xml文档添加、删除、更新索引 。Solr 搜索只需要发送 HTTP GET 请求,然后对 Solr 返回 Xml、json 等格式的查询结果进行解析,组织页面布局。Solr不提供构建UI的功能,Solr提供了一个管理界面,通过管理界面可以查询Solr的配置和运行情况。
solr是基于lucene开发企业级搜索服务器,实际上就是封装了lucene。
Solr 是一个独立的企业级搜索应用服务器,它对外提供类似于 Web-service的API 接口。用户可以通过 http 请求,向搜索引擎服务器提交一定格式的文件,生成索引;也可以通过提出查找请求,并得到返回结果
Solr类似 webservice,调用接口,实现增加,修改,删除,查询索引库。
solr特性
- 高级的全文搜索功能
- 专为高通量的网络流量进行的优化
- 基于开放接口(xml和http)的标准
- 综合的html管理界面
- 可伸缩性-能够有效地复制到另外一个Solr搜索服务器
- 使用xml配置达到灵活性和适配性
- 可扩展的插件体系
Solr与Lucene的区别
Lucene是一个开放源代码的全文检索引擎工具包,它不是一个完整的全文检索引擎,Lucene提供了完整的查询引擎和索引引擎,目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现全文检索的功能,或者以Lucene为基础构建全文检索引擎。
Solr的目标是打造一款企业级的搜索引擎系统,它是一个搜索引擎服务,可以独立运行,通过Solr可以非常快速的构建企业的搜索引擎,通过Solr也可以高效的完成站内搜索功能。
Solr 类似 webservice,提供接口,调用接口,发送一些特点语句,实现增加,删除,修改,查询。
二、solr 安装(mac)
- 首先安装 jdk 和 jre
- 安装solr:
brew install solr
安装solr,可以通过brew edit solr
修改要安装的版本 - 启动 solr:
solr start
。- 默认端口号
8083
,如果该端口被占用,则会自动切换可用的端口。
- 启动成功后再浏览器输入URLhttp://127.0.0.1:8983,访问 solr 后台管理界面
- 默认端口号
- 创建 core(可以理解为mysql中的数据库,即一个服务可以有多个库):
solr create -c test_core
- 测试分词
由于solr自带的分词器无法将中文根据语义分词,需要引入中文分词器 IKAnalyzer
三、IKAnalyzer 安装
下载地址:https://github.com/jxlwqq/Installing-Solr-and-indexing-MySQL-on-macOS/tree/master/file
1. 下载必要的组件
- IKAnalyzer jar 包: ik-analyzer-solr5-5.x.jar
- IKAnalyzer 配置文件: IKAnalyzer.cfg.xml
- 词库: mydict.dic 和 stopword.dic
下载后,将相关文件复制到相应的目录中,操作目录如下:
cp ik-analyzer-solr5-5.x.jar /usr/local/Cellar/solr/7.3.1/server/solr-webapp/webapp/WEB-INF/lib/
mkdir /usr/local/Cellar/solr/7.3.1/server/solr-webapp/webapp/WEB-INF/lib/classes/
cp IKAnalyzer.cfg.xml /usr/local/Cellar/solr/7.3.1/server/solr-webapp/webapp/WEB-INF/lib/classes/
cp mydict.dic /usr/local/Cellar/solr/7.3.1/server/solr-webapp/webapp/WEB-INF/lib/classes/
cp stopword.dic /usr/local/Cellar/solr/7.3.1/server/solr-webapp/webapp/WEB-INF/lib/classes/
2. 修改 managed-schema 文件
// test_core 仓库下
vi /usr/local/Cellar/solr/7.3.1/server/solr/test_core/conf/managed-schema
在schema
标签内追加以下内容:
<fieldType name="text_ik" class="solr.TextField">
<analyzer class="org.wltea.analyzer.lucene.IKAnalyzer"/>
</fieldType>
<field name="text_ik" type="text_ik" indexed="true" stored="true" multiValued="false"/>
3. 重启测试
进行重启:solr restart
进行测试:刷新页面,进入到 test_core 仓库下
测试成功!
四、solr 常用命令
- 其他命令
查看版本:solr -version
重启:solr restart
关闭:solr stop -all(或者指定端口号:solr stop -p 8983)
创建集合:solr create -c [集合名称]
删除集合:solr delete -c [集合名称]
删除数据
<delete>
<query>*:*</query>
</delete>
<commit/>
删除字段
{
"delete-field" : {
"name" : "字段名称"
},
"delete-field" : {
"name" : "字段名称"
}
}
提交的地址
POST http://localhost:8983/solr/集合名称/schema
添加字段
name: 字段名称 type: 字段类型 stored: 是否保存 indexed: 是否索引
{
"add-field" : {
"name" : "字段名称",
"type" : "text_ik",
"stored" : "true",
"indexed" : "true"
},
"add-field" : {
"name" : "字段名称",
"type" : "text_ik",
"stored" : "true"
}
}
提交地址
POST http://localhost:8983/solr/集合名称/schema
还可以在管理员界面添加
五、solrJ
SolrJ 是操作 Solr官方提供的Java客户端,它底层使用HttpClient
封装了大量的方法,使用它可以非常方便的对Solr索引进行增加、删除、修改、查询操作。
1. 增加maven依赖
<dependency>
<groupId>org.apache.solr</groupId>
<artifactId>solr-solrj</artifactId>
<version>7.3.1</version>
</dependency>
2. 创建 Model
public class Man {
@Field("id")
private String id;
@Field("name")
private String name;
@Field("age")
private Integer age;
// get()、set() ...
}
3. 创建演示类
public class SolrJExample {
private HttpSolrClient solrClient;
//由于目前只有一个Core,就直接写在url上拉,这里不写的话CRUD操作前都要声明被操作的Core,切记。
private final String solrUrl = "http://localhost:8983/solr/test_core";
// 初始化客户端
@Before
public void before() {
solrClient = new HttpSolrClient.Builder(solrUrl)
.withConnectionTimeout(10000)
.withSocketTimeout(60000)
.build();
//由于目前只有一个Core,就直接写在url上拉,这里不写的话CRUD操作前都要声明被操作的Core,切记。
}
// 提交,关闭会话
@After
public void after() throws IOException, SolrServerException {
solrClient.commit();
solrClient.close();
}
}
4. 添加索引
// 添加一个用户
@Test
public void addOne() throws IOException, SolrServerException {
solrClient.addBean(new Man("2", "张三", 48));
}
// 添加多个用户
@Test
public void addList() throws IOException, SolrServerException {
int i = 1;
int max = 100;
List<Man> userList = new ArrayList<Man>(100);
while (i <= max) {
userList.add(new Man(String.valueOf(i), "土豆-" + i, i));
i++;
}
solrClient.addBeans(userList);
}
5. 删除、查询及类完整代码
public class SolrJExample {
private HttpSolrClient solrClient;
//由于目前只有一个Core,就直接写在url上拉,这里不写的话CRUD操作前都要声明被操作的Core,切记。
private final String solrUrl = "http://localhost:8983/solr/test_core";
// 初始化客户端
@Before
public void before() {
solrClient = new HttpSolrClient.Builder(solrUrl)
.withConnectionTimeout(10000)
.withSocketTimeout(60000)
.build();
//由于目前只有一个Core,就直接写在url上拉,这里不写的话CRUD操作前都要声明被操作的Core,切记。
}
// 提交,关闭会话
@After
public void after() throws IOException, SolrServerException {
solrClient.commit();
solrClient.close();
}
// 添加一个用户
@Test
public void addOne() throws IOException, SolrServerException {
solrClient.addBean(new Man("2", "张三", 48));
}
// 添加多个用户
@Test
public void addList() throws IOException, SolrServerException {
int i = 1;
int max = 100;
List<Man> userList = new ArrayList<Man>(100);
while (i <= max) {
userList.add(new Man(String.valueOf(i), "土豆-" + i, i));
i++;
}
solrClient.addBeans(userList);
}
@Test
public void delete() throws IOException, SolrServerException {
solrClient.deleteById("1");//删除一个
solrClient.deleteByQuery("*:*");//删除所有
}
@Test
public void query() throws IOException, SolrServerException {
//构造查询参数
SolrQuery query = new SolrQuery("name:土豆*");//查询姓名包含土豆的User
query.set("fl", "id,name");//返回字段值,不返回则为null
query.setSort("age", SolrQuery.ORDER.asc);//按年龄升序
query.setHighlight(true); //开启高亮
query.setHighlightFragsize(10); //返回的字符个数
query.setHighlightRequireFieldMatch(true);
query.setHighlightSimplePre("<font color=\"red\">"); //前缀
query.setHighlightSimplePost("</font>"); //后缀
query.setParam("hl.fl", "name"); //高亮字段
query.setStart(0); //分页参数
query.setRows(10); //分页参数
//获得查询结果
QueryResponse response = solrClient.query(query);
//转换为Java Bean
List<Man> userList = response.getBeans(Man.class);
Assert.assertNotNull(userList);
Assert.assertTrue(userList.size() == 10);
}
}
参考资料
- Solr 6.2.0 solr-solrj API
- macOS安装Solr并索引MySQL
- solr安装、使用、配置中文分词器
- solr 学习与测试
- https://blog.csdn.net/lzx1104/article/category/2223439
其他官方资料
solr文档
- Solr指南(Tutorial)
- 新用户鼓励从the Solr tutorial开始看。
- 发布文档 (Release Documentation)
在每个Solr的二进制发布包中,你可以找到一份Solr tutorial, 一个(版本)修改的详细列表,和所有代码的JavaDocs.
对于各个主要的活跃开发分支,最近release的指南文档也可以在线找到:
如http://lucene.apache.org/solr/4_10_1/index.html
注:Release文档主要是JavaDocs,对于阅读Solr源码有帮助,但对Solr的使用参考性不大。
- Apache Solr参考指南(Reference Guide)
从Solr4.4开始,每个release有一份详细的参考指南可以以PDF下载。
注:Solr Reference Guide是一份较详细的Solr使用文档(推荐),对于理解和使用Solr有较大帮助。
- 其他文档
注:Solr Wiki是比较早的参考文档,可能有的内容已过期,可结合新的(4.4以后)参考指南来看。
- Solr版本管理
Solr代码版本管理