一、 Solr 介绍
1 全文检索
什么叫做全文检索呢?这要从我们生活中的数据说起。
我们生活中的数据总体分为两种:结构化数据和非结构化数据。
1)结构化数据:指具有固定格式或有限长度的数据,如数据库,元数据等。
2)非结构化数据:指不定长或无固定格式的数据,如邮件,word 文档等。
非结构化数据又一种叫法叫全文数据。
按照数据的分类,搜索也分为两种:
1)对结构化数据的搜索:如对数据库的搜索,用 SQL 语句。
2)对非结构化数据的搜索:如利用 windows 的搜索也可以搜索文件内容,Linux
下的 grep 命令,再如用 Google 和百度可以搜索大量内容数据。
2 Lucene
Lucene 是一个高效的,基于 Java 的全文检索库。
Lucene 是 apache 软件基金会 4 jakarta 项目组的一个子项目,是一个开放源代码的全
文检索引擎工具包,但它不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,
Lucene 的目的是为软件开发人员提供一个简单易用的工具包,以方便的在目标系统中实现
全文检索的功能,或者是以此为基础建立起完整的全文检索引擎。Lucene 是一套用于全文
检索和搜寻的开源程序库,由 Apache 软件基金会支持和提供。Lucene 提供了一个简单却
强大的应用程序接口,能够做全文索引和搜寻。在 Java 开发环境里 Lucene 是一个成熟的
免费开源工具。就其本身而言,Lucene 是当前以及最近几年最受欢迎的免费 Java 信息检
索程序库。
3 Solr 简介
Solr 是基于 Lucene 的面向企业搜索的 web 应用
Solr 是一个独立的企业级搜索应用服务器,它对外提供类似于 Web-service 的 API 接
口。用户可以通过 http 请求,向搜索引擎服务器提交一定格式的 XML 文件,生成索引;也
可以通过 Http Get 操作提出查找请求,并得到 xml/json 格式的返回结果。
Solr 是一个高性能,采用 Java5 开发,基于 Lucene 的全文搜索服务器。同时对其进行
了扩展,提供了比 Lucene 更为丰富的查询语言,同时实现了可配置、可扩展并对查询性能
进行了优化,并且提供了一个完善的功能管理界面,是一款非常优秀的全文检索引擎。
文档通过 Http 利用 XML 加到一个搜索集合中。查询该集合也是通过 http 收到一个
XML/JSON 响应来实现。它的主要特性包括:高效、灵活的缓存功能,垂直搜索功能,高
亮显示搜索结果,通过索引复制来提高可用性,提供一套强大 Data Schema 来定义字段,
类型和设置文本分析,提供基于 Web 的管理界面等。
二、 Solr 单机版安装
1 安装环境
1.1安装 jdk
1.1.1JDK 版本:
jdk-8u11-linux-x64.tar.gz
1.1.2环境变量配置
export JAVA_HOME=/usr/local/jdk
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export PATH=$JAVA_HOME/bin:$PATH
1.2安装 tomcat
1.2.1Tomcat 版本
apache-tomcat-7.0.47.tar.gz
2 安装 Solr
Solr 版本:solr-4.10.3.tgz.tgz
2.1Solr 是由两个部分构成:
1) Solr 的 web 服务
2) Solr 的索引库
2.2上传 Solr 压缩包
2.3解压 Solr 压缩包
2.4Solr 的目录介绍
bin:启动 solr 的一些脚本,但是需要依赖 jeety 容器
contrib:存放的是 solr 对第三方插件支持的内容
dist:solr 编译后所产生一些文件夹。War 或者是 jar
example:是 solr 的案例。在该目录下有两个文件夹对于我们来说比较重要。
1) webapps:在该目录中存放了一个 solr 的 war 包。与 dist 目录下的那个 war 文 件是
同一个,只是存放的目录及名称不同而已。
2) solr: 是 solr 的一个标准的索引库示例。
3) lib/ext:该目录下存放的是一些日志处理器的 jar 包。Solr 的 web 服务也要依赖于日志
处理的 jar 包。所以我们在安装 solr 服务时,需要将该目录下的 jar 拷贝给 solr 服务
2.5安装 Solr 服务
其实安装 solr 服务就是将 solr 的 war 包,拷贝到 tomcat 的 webapps 目录下。
2.6启动 tomcat,解压 war 包
查看 tomcat 的启动日志,查看是否做 war 的解压 tailf logs/catalina.out
2.7添加服务中所依赖的 jar 包
由于我们在解压后的 solr 的项目中,需要依赖一些日志处理的 jar 包。所以我们在添加
依赖的 jar 包时,需要将原来的 war 删除掉。否则 tomcat 再次启动时,会将原来的目录覆盖
掉。那么新添加的 jar 包也就没了。注意:在删除 war 包时,一定要在 tomcat 关闭的状态下
删除 war 包。如果在 tomcat 启动状态下删除 war 包,那么 tomcat 在关闭时会将解压的目录一并的也删除掉。
2.8安装 solr 索引库
在 solr 的解压目录的 example 目录下有个 solr 的目录,就是 solr 的一个基本的索引库示例。
2.9拷贝索引库
将该索引库拷贝到指定目录下(可以是任意目录),虽然具备任意性。但是也不能太随便。 应该放到/usr/local/solrhome。先创建 solrhome 目录
2.10solr 的服务中配置索引库
在 solr 的服务中配置索引库的位置注意:需要配置的路径为索引库的根。可以使用 linux 中的 pwd 命令查看绝对路径。将该路径添加到 solr 服务中的 web.xml 文件中 Solr 服务在启动时,是通过他的 web.xml 文件中的节点配置获取索引库的绝对位置的。vim web.xml 在web.xml 中找到<env-entry>.注意:该节点默认是注释状态的,我们需要先去掉注释。然后将拷贝的索引库的路径添加到该节点的<env-entry-value>节点中
2.11访问 Solr 服务
启动 tomcat 通过 solr 的管理页面可以对 solr 进行操作了。启动 tomcat 后,打开浏览器输入 solr 的访问 url 就可以访问 solr 服务了
3 Solr 索引库
3.1solr home 目录结构
3.1.1solr.xml 配置 solr 集群
3.1.2collection1(索引库:solr core)
3.1.3core.properties 设置索引库的名称
3.1.4data 存放索引
3.1.5conf 索引库的配置目录
3.1.5.1 schema.xml:配置字段以及字段类型
3.2索引库配置
schema.xml 是用来定义索引数据中的域的,包括域名称,域类型,域是否索引,是否
分词,是否存储等等。
3.2.1如何定义索引库中的 Field
<field>:定义域
<field name="_version_" type="long" indexed="true" stored="true"/>
name:表示域的名称,是强制必须有的属性
type:域类型的名称,与 fieldType 元素的 name 属性值对应,是强制必须有的属性
indexed:是否参与检索。true 即表示需要对该域进行索引。默认值为 false
stored:是否将 field 域中的内容存储到文档域,简单通俗的来说,就是你这一个field 需不需要被当作查询结果返回。
required:表示这个域是否是必须要在 document 中存在,默认值为 false,如果此配
置项设为 true,则你的 document 中必须要添加此域,否则你创建索引时会抛异常。
3.2.2如何定义索引库中的 FieldType
<fieldType>:定义域的类型
<fieldType name="string" class="solr.StrField" sortMissingLast="true" />
Name:域类型的名称,作为域类型标识符存在,在定义域(Field)时使用的类型
(FieldType)属性就是域类型的名称。
Class:域类型的数据类型,该属性指向的是 solr 中的已定义的类型,或者是用户定义的类型,域类型中的数据会被初始化成 class 执行类类的对象。
sortMissingFirst/sortMissingLast:控制当排序域的值不存在时该文档(Document)所在队列的位置。true 是则在队头/队尾
3.2.3如何定义索引库中的 CopyField
<copyField>:复制域。可实现更新与查询分离
<copyField source="item_title" dest="item_keywords"/>
Source:源域
Dest:目标域
3.2.4Solr 的索引机制
3.2.4.1 正排索引(正向索引)
正排索引是以文档的 ID 为关键字,索引文档中每个字的位置信息,查找时扫描索引中每个文档中字的信息直到找出所有包含查询关键字的文档。
但是在查询的时候需对所有的文档进行扫描以确保没有遗漏,这样就使得检索时间大大 延长,检索效率低下。
尽管正排索引的工作原理非常的简单,但是由于其检索效率太低,除非在特定情况下, 否则实用性价值不大。
正排索引从文档编号找词
3.2.4.2 倒排索引(反向索引)
对数据进行分析,抽取出数据中的词条,以词条作为 key,对应数据的存储位置作为
value,实现索引的存储。这种索引称为倒排索引。
当 solr 存储文档时,solr 会首先对文档数据进行分词,创建索引库和文档数据库。所谓
的分词是指:将一段字符文本按照一定的规则分成若干个单词。
倒排索引是从词找文档编号
3.2.5配置中文分词器(IK Analyzer)
3.2.5.1 上传中文分词器 jar 包,以及配置文件
3.2.5.2 将中文分词器的配置文件以及 jar包拷贝到 Solr 所对应的目录下
将配置文件需要放到 classes 目录下。
在 solr 中的 WEB-INF 下时没有 classes 目录的。我们需要先创建一个
Jar 包放到 WEB-INF/lib 目录下。
3.2.5.3 在 schema.xml 中配置中文分词器
<fieldType name="text_ik" class="solr.TextField">
<analyzer class="org.wltea.analyzer.lucene.IKAnalyzer"/>
</fieldType>
3.2.5.4 测试
3.3Solr 管理页面操作
3.3.1Dashboard(仪表盘)
访问 http://localhost:8080/solr 时,出现该主页面,可查看到 solr 运行时间、solr 版本,系统内存、虚拟机内存的使用情况
3.3.2Logging(日志)
显示 solr 运行出现的异常或错误
3.3.3Core Admin (core 管理)
主要有 Add Core(添加核心),Unload(卸载核心),Rename(重命名核心),Reload(重新加载核心),Optimize(优化索引库)
Add Core 是添加 core : 主 要 是 在 instanceDir 对 应 的 文 件 夹 里 生 成 一 个 core.properties 文件
name:给 core 起的名字;
instanceDir:与我们在配置 solr 到 tomcat 里时的 solr_home 里新建的 core
文件夹名一致;
dataDir:确认 Add Core 时,会在 new_core 目录下生成名为 data 的文件夹
config:new_core 下的 conf 下的 config 配置文件(solrconfig.xml)
schema: new_core 下的 conf 下的 schema 文件(schema.xml)
3.3.4Java Properties
可查看到 java 相关的一些属性的信息
3.3.4Java Properties
可查看到 java 相关的一些属性的信息
3.3.5Thread Dump
查看每个线程的详细信息,以及状态信息
3.3.6Core Selecter(core 选择器)
3.3.6.1 overview(概览)
包含基本统计如当前文档数;和实例信息如当前核心的配置目录
3.3.6.2 Analysis(分析)
检验分词效果
3.3.6.3 Dataimport(导入数据)
3.3.6.4 Documents
Documents (索引文档)索引的相关操作,如:增加,修改,删除等
在如下页面,选择/update ,文档格式选择 json ,然后 submit 提交。这样 索引就增加上了。修改与增加一样,都是/update ,删除为/delete 。 成功之后,我们去 query 里查询数据就能查到我们刚添加的数据.
3.3.6.5 Files 文件夹
solr_home 下的 core 下的 conf 下的相关文件,可单击查看里面的内容
3.3.6.6 Ping
查看当前核心库还是否工作的以及响应时间
3.3.6.7 Plugins /stats
Solr 自带的一些插件以及我们安装的插件的信息以及统计
3.3.6.8 Query(查询页面)
查询的结果要显示哪个字段,就得将 schema.xml 文件配置字段时的 stored 属性设为 true
Request-Handler(qt): 请求处理器
q: 查询字符串(必须的)。:表示查询所有;keyword:尚学堂 表示按关键字“尚学堂”
查询
fq: filter query 过滤查询。使用 Filter Query 可以充分利用 Filter Query Cache,提高检索性能。作用:在 q 查询符合结果中同时是 fq 查询符合的(类似求交集),例如:
q=mm&fq=date_time:[20081001 TO 20091031],找关键字 mm,并且 date_time 是 20081001到 20091031 之间的。
sort: 排序。格式如下:字段名 排序方式;如 id desc 表示按 id 字段降序排列查询结果。
start,rows:表示查回结果从第几条数据开始显示,共显示多少条。
fl: field list。指定查询结果返回哪些字段。多个时以空格“ ”或逗号“,”分隔。不指
定时,默认全返回。
df: default field 默认的查询字段,一般默认指定。
Raw Query Parameters: 原始查询参数的
wt: write type。指定查询输出结果格式,我们常用的有 json 格式与 xml 格式。在 solrconfig.xml 中定义了查询输出格式:xml、json、python、ruby、php、csv。
indent: 返回的结果是否缩进,默认关闭,用 indent=true | on 开启,一般调试 json,php,phps,ruby 输出才有必要用这个参数。
debugQuery: 设置返回结果是否显示 Debug 信息。
dismax:
edismax:
hl: high light 高亮。hl=true 表示启用高亮
hl.fl : 用空格或逗号隔开的字段列表(指定高亮的字段)。要启用某个字段的 highlight 功能,就得保证该字段在 schema 中是 stored。
hl.simple.pre: 设置高亮显示的 html 标记的开始标记
hl.simple.post:设置高亮显示的 html 标记的结束标记
hl.requireFieldMatch: 如果置为 true,除非该字段的查询结果不为空才会被高亮。它 的默认值是 false,意味 着它可能匹配某个字段却高亮一个不同的字段。如果 hl.fl 使用了通 配符,那么就要启用该参数。尽管如此,如果你的查询是 all 字段(可能是使用 copy-field 指 令),那么还是把它设为 false,这样搜索结果能表明哪个字段的查询文本未被找到
hl.usePhraseHighlighter:如果一个查询中含有短语(引号框起来的)那么会保证一 定要完全匹配短语的才会被高亮。
hl.highlightMultiTerm:如果使用通配符和模糊搜索,那么会确保与通配符匹配的 term 会高亮。默认为 false,同时 hl.usePhraseHighlighter 要为 true。
facet:分组统计,在搜索关键字的同时,能够按照 Facet 的字段进行分组并统计。
facet.query:Facet Query 利用类似于 filter query 的语法提供了更为灵活的 Facet.通 过 facet.query 参数,可以对任意字段进行筛选。
facet.field:需要分组统计的字段,可以多个。
facet.prefix: 表示 Facet 字段值的前缀。比如 facet.field=cpu&facet.prefix=Intel, 那么对 cpu 字段进行 Facet 查询,返回的 cpu 都是以 Intel 开头的, AMD 开头的 cpu 型号将不会被统计在内。
spatial:
spellcheck: 拼写检查。
3.3.6.9 Replication
显示你当前 Core 的副本,并提供 disable/enable 功能
3.3.6.10 Schema
展示该 Core 的 shema.xml 文件中的内容
三、 在索引库中定义业务字段
1 表结构
CREATE TABLE `tb_item` (
`id` bigint(20) NOT NULL COMMENT '商品id,同时也是商品编号',
`title` varchar(100) NOT NULL COMMENT '商品标题',
`sell_point` varchar(500) DEFAULT NULL COMMENT '商品卖点',
`price` bigint(20) NOT NULL COMMENT '商品价格,单位为:分',
`num` int(10) NOT NULL COMMENT '库存数量',
`barcode` varchar(30) DEFAULT NULL COMMENT '商品条形码',
`image` varchar(500) DEFAULT NULL COMMENT '商品图片',
`cid` bigint(10) NOT NULL COMMENT '所属类目,叶子类目',
`status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '商品状态,1-正常,2-下架,3-删除',
`created` datetime NOT NULL COMMENT '创建时间',
`updated` datetime NOT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `cid` (`cid`),
KEY `status` (`status`),
KEY `updated` (`updated`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='商品表';
2 定义域
<field name="id" type="string" indexed="false" stored="true" required="true" multiValued="false" />
<field name="item_title" type="text_ik" indexed="true" stored="true"/>
<field name="item_sell_point" type="text_ik" indexed="true" stored="true"/>
<field name="item_price" type="long" indexed="false" stored="true"/>
<field name="item_image" type="string" indexed="false" stored="true" />
3 定义默认检索域
<field name="item_keywords" type="text_ik" indexed="true" stored="false" multiValued="true"/>
<copyField source="item_title" dest="item_keywords"/>
<copyField source="item_sell_point" dest="item_keywords"/>
四、 SolrJ 的使用
1 什么是 SolrJ
solrJ 是访问 Solr 服务的 JAVA 客户端,提供索引和搜索的请求方法,SolrJ 通常嵌入在
业务系统中,通过 solrJ 的 API 接口操作 Solr 服务。
单独使用时还需要导入commons-logging.
2 测试 SolrJ
2.1创建项目
2.2修改 POM 文件添加 SolrJ 坐标
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.sxt</groupId>
<artifactId>sorlJDemo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.apache.solr</groupId>
<artifactId>solr-solrj</artifactId>
<version>4.10.3</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
</project>
2.3向索引库中添加文档
package com.sxt.test;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.impl.HttpSolrServer;
import org.apache.solr.common.SolrInputDocument;
public class Test {
public static void main(String[] args) throws Exception {
Test.solrInsert();
}
public static void solrInsert() throws Exception {
//创建一个solrJ的连接对象
SolrServer server = new HttpSolrServer("http://192.168.226.130:8080/solr");
//创建一个solr的 文档对象
SolrInputDocument docu = new SolrInputDocument();
//向文档对象中添加需要插入到索引库的内容
docu.addField("id", "LaoHei");
docu.addField("item_title", "太好了");
docu.addField("item_price", 1000);
//将文档插入到solr的索引库中
server.add(docu);
//事务的提交
server.commit();
}
}
测试:
2.4删除索引库文档
/**
* 删除索引库中的文档
* @throws Exception
*/
public static void solrDelete() throws Exception {
//创建一个solrJ的连接对象
SolrServer server = new HttpSolrServer("http://192.168.226.130:8080/solr");
//根据ID删除
//server.deleteById("LaoHei");
//根据查询删除
server.deleteByQuery("*:*");
server.commit();
}
2.5查询索引库中的文档
/**
* 查询索引库中的文档
* @throws Exception
*/
public static void solrSearch() throws Exception {
//创建一个solrJ的连接对象
SolrServer server = new HttpSolrServer("http://192.168.226.130:8080/solr");
//创建查询条件
SolrQuery query = new SolrQuery();
query.setQuery("尚学堂0");
query.set("df", "item_keywords");
//设置分页
query.setStart(0);
//执行查询
//QueryResponse:封装查询的结果集
QueryResponse res = server.query(query);
SolrDocumentList list = res.getResults();
//list.getNumFound() 数据总条数
System.out.println("总条数:"+list.getNumFound());
for (SolrDocument solrDocument : list) {
System.out.println(solrDocument.get("item_title"));
System.out.println(solrDocument.get("item_price"));
}
}