目录
solr介绍
环境搭建
API操作
solr介绍
首先需要了解一下全文检索:
1、什么是全文搜索引擎?
百度百科中的定义:
全文搜索引擎是目前广泛应用的主流搜索引擎。它的工作原理是计算机索引程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置,当用户查询时,检索程序就根据事先建立的索引进行查找,并将查找的结果反馈给用户的检索方式。这个过程类似于通过字典中的检索字表查字的过程。
2、它们的索引建立都是根据倒排索引的方式生成索引,何谓倒排索引?
维基百科
倒排索引(英语:Inverted index),也常被称为反向索引、置入档案或反向档案,是一种索引方法,被用来存储在全文搜索下某个单词在一个文档或者一组文档中的存储位置的映射。它是文档检索系统中最常用的数据结构。
3、Lucene
Lucene是一个Java全文搜索引擎,完全用Java编写。Lucene不是一个完整的应用程序,而是一个代码库和API,可以很容易地用于向应用程序添加搜索功能。
Lucene通过简单的API提供强大的功能:
可扩展的高性能索引
在现代硬件上超过150GB /小时
小RAM要求 - 只有1MB堆
增量索引与批量索引一样快
索引大小约为索引文本大小的20-30%
强大,准确,高效的搜索算法
排名搜索 - 首先返回最佳结果
许多强大的查询类型:短语查询,通配符查询,邻近查询,范围查询等
现场搜索(例如标题,作者,内容)
按任何字段排序
使用合并结果进行多索引搜索
允许同时更新和搜索
灵活的分面,突出显示,连接和结果分组
快速,内存效率和错误容忍的建议
可插拔排名模型,包括矢量空间模型和Okapi BM25
可配置存储引擎(编解码器)
跨平台解决方案
作为Apache许可下的开源软件提供 ,允许您在商业和开源程序中使用Lucene
100%-pure Java
可用的其他编程语言中的实现是索引兼容的
4、Solr
Apache Solr是一个基于名为Lucene的Java库构建的开源搜索平台。它以用户友好的方式提供Apache Lucene的搜索功能。作为一个行业参与者近十年,它是一个成熟的产品,拥有强大而广泛的用户社区。它提供分布式索引,复制,负载平衡查询以及自动故障转移和恢复。如果它被正确部署然后管理得好,它就能够成为一个高度可靠,可扩展且容错的搜索引擎。很多互联网巨头,如Netflix,eBay,Instagram和亚马逊(CloudSearch)都使用Solr,因为它能够索引和搜索多个站点。
主要功能列表包括:
全文搜索
突出
分面搜索
实时索引
动态群集
数据库集成
NoSQL功能和丰富的文档处理(例如Word和PDF文件)
es和solr的对比:可以查看我的另一篇博客:https://blog.csdn.net/qq_35950932/article/details/102587466
环境搭建
在solr5以前solr的启动都有tomcat作为容器,但是从solr5以后solr内部集成jetty服务器,可以通过bin目录中脚本直接启动。就是从solr5以后跟solr4最大的区别是被发布成一个独立的应用。
下载以及解压包目录:
目前solr已经发布了8.0的版本,与之前的旧版本在配置文件上有一些改动;
solr所支持的环境:JDK8以上,因为solr基于lucene8, lucene8需要jdk8或以上版本
下载地址:https://www.apache.org/dyn/closer.lua/lucene/solr/8.2.0/solr-8.2.0.zip
下载后进行解压,此种方式是直接在bin下启动,不需要在tomcat下启动:
bin:可执行文件
solr的基本运行命令:
启动命令:solr.cmd start -m 2g (启动时占用的内存空间)
手动创建索引库命令 solr.cmd create -c xxx
停止命令:solr.cmd stop -all
删除索引命令:solr.cmd delete -c yourCollection
example:一些案例数据
server:索引库的相关信息,自己的索引库和依赖包等文件所依赖的jar包:
使用的中文分词器(当然也支持高版本的分词*)
mysql驱动(**需要匹配自己的mysql版本)
数据库依赖包
详细配置信息:-------很简单就是在配置文件中加点东西
一、修改配置文件
managed-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" />
``` 添加在
```java
<schema name="example-data-driven-schema" version="1.6">
二、同步mysql5.8数据:(需要和自己的mysql版本一致,我使用的是mysql5.8)
对应的是mysql5.8的版本
将mysql驱动包导入到solr-8.0.0\server\solr-webapp\webapp\WEB-INF\lib
在自己新增的索引库中新建data-config.xml
修改配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<dataConfig>
<dataSource name="source" type="JdbcDataSource"
driver="com.mysql.cj.jdbc.Driver" ---------高版本的数据库
url="**jdbc:mysql://localhost:xxxx/xxxdb?serverTimezone=UTC&useSSL=false**"
user="root"
password="123456"
batchSize="0"
/>
<document>
<entity name="af_renyuan" dataSource="source"
query="select ID,XM,SFZH,XGZDW,YGZDW,ZJ02 from af_renyuan">
<field column="ID" name="rid" />
<field column="XM" name="rname" />
<field column="SFZH" name="rsfzh" />
<field column="XGZDW" name="rxgzdw" />
<field column="YGZDW" name="rygzdw" />
<field column="ZJ02" name="rzj02" />
</entity>
</document>
</dataConfig>
column-----数据库字段 name------映射的实体
三、将D:\tydic\solr\9-28\solr-8.0.0\dist下
数据库依赖包导入到solr-8.0.0\server\solr-webapp\webapp\WEB-INF\lib
Solrconfig.xml
<requestHandler name="/dataimport"
class="org.apache.solr.handler.dataimport.DataImportHandler">
<lst name="defaults">
<str name="config">data-config.xml</str>
</lst>
</requestHandler>
<!-- SearchHandler
http://wiki.apache.org/solr/SearchHandler
For processing Search Queries, the primary Request Handler
provided with Solr is "SearchHandler" It delegates to a sequent
of SearchComponents (see below) and supports distributed
queries across multiple shards
-->
四、最关键一步:
需要手动创建索引库
命令:Solr.cmd create -c xxx
然后在managed-schema中填写域
<field name="rid" type="string" indexed="true" stored="true"/>
<field name="rname" type="text_ik" indexed="true" stored="true"/>
<field name="rsfzh" type="string" indexed="true" stored="true"/>
<field name="rxgzdw" type="text_ik" indexed="true" stored="true"/>
<field name="rygzdw" type="text_ik" indexed="true" stored="true"/>
<field name="rzj02" type="text_ik" indexed="true" stored="true"/>
type:普通类型与text_ik中文分词
到此基本的配置就完成了;
如果不想使用solr的主键id,可以指定自己的主键字段
修改id为自定义的rid
**<field name="rid" type="string" indexed="true" stored="true" required="true" multiValued="false" />
<!--<field name="rid" type="string" indexed="true" stored="true"/>-->
<!-- 修改uniqueKey为rid-->
<!-- <uniqueKey>id</uniqueKey> -->
<uniqueKey>rid</uniqueKey>**
删除数据
**<delete><query>*:*</query></delete>
<commit/>**
API操作
普通查询:
单机版api:SolrClient
private static SolrClient client;
private static String url;
//初始化连接
static {
url = StartupProUtil.getVOfThread("spring.solr.url");
System.out.println(url);
client = new HttpSolrClient.Builder(url).build();
}
public static Map<String,Object> query(String param) throws SolrServerException, IOException {
SolrQuery query = new SolrQuery();
/* //此种处理手段不能匹配所有的情况
if(flageName.length()>=3&&flageName.length()<4){
System.out.println("全名字匹配......");
query.set("defType","edismax");
//设置匹配度-----全词匹配 mm可以设置为整数,如2,代表至少匹配两个词项,如果输入词项少于两个,那么要全部匹配才行。
query.set("mm",flageName.length());
query.setQuery("rname:"+flageName);
}else{
}*/
//===============================条件查询======================================================
//and 条件查询
query.setQuery("rname:"+flageName +" and rxgzdw:"+params+" and rygzdw:"+params+" and rzj02:"+params+" and rsfzh:"+params+"");
//or 条件查询
//query.setQuery("rname:"+params+" or rxgzdw:"+params+" or rygzdw:"+params+" or rzj02:"+params+" or rsfzh:"+params+"");
//=============================================================================================
//加入评分字段
query.setParam("fl","rid","rname", "rxgzdw","rygzdw","rsfzh","rzj02","score");
//==============================高亮设置开始===================================================
// 设置高亮,以下两种方式都行(相当于开启高亮功能)
query.setParam("hl", "true"); // highlighting
//hl.fl: 用空格或逗号隔开的字段列表。要启用某个字段的highlight功能,就得保证该字段在schema中是stored。
//如果该参数未被给出,那么就会高亮默认字段 standard handler会用df参数,dismax字段用qf参数。
//你可以使用星号去方便的高亮所有字段。如果你使用了通配符,那么要考虑启用hl.requiredFieldMatch选项。
query.setParam("hl.fl","rname", "rxgzdw","rygzdw","rsfzh","rzj02");
//高亮显示字段前后添加html代码
// 设置高亮
query.setHighlightSimplePre("<font color=\"red\">");
query.setHighlightSimplePost("</font>");//高亮时显示的格式,默认是<em></em>
//query.setHighlightSnippets(3);
//这是highlighted片段的最大数。默认值为1,也几乎不会修改。获取高亮分片数,一般搜索词可能分布在文章中 的不同位置,其所在一定长度的语句即为一个片段,默认为1,但根据业务需要有时候需要多取出几个分片。
//如果某个特定的字段的该值被置为0,这就表明该字段被禁用高亮了
//query.setHighlightFragsize(0);// 每个snippet返回的最大字符数。默认是100.如果为0,那么该字段不会被fragmented且整个字段的值会被返回。大字段时不会这么做
//query.set("hl.usePhraseHighlighte",true);//如果一个查询中含有短语(引号框起来的)那么会保证一定要完全匹配短语的才会被高亮。
//有时我们查询根据条件“java OR (empId:1000 AND empId:1001)”搜索时,结果如果高亮显示,可能出现1000,1001数字也会高亮,
//但是我们只希望java关键字高亮,这个时候可以用下面的方法,只对lucene和solr关键字进行高亮显示(solr不作为搜索条件也可以)
//query.setParam("hl.q","lucene solr");
//==============================高亮配置结束===============================================
//==============================排序规则在solrconfig.xml中进行设置生效=====================
/*query.addSort("rname", SolrQuery.ORDER.desc);
query.addSort("rxgzdw", SolrQuery.ORDER.desc);
query.addSort("rygzdw", SolrQuery.ORDER.desc);
query.addSort("rzj02", SolrQuery.ORDER.desc);*/
//=========================================================================================
//设置分页
query.setStart(0);
//查询最大 该参数就是控制条数 设定为Integer最大值
query.setRows(Integer.MAX_VALUE);
Map<String,Object> map = new HashMap<>();
List<Person> perList = new ArrayList<>();
Set<String> set = new HashSet<>();
try {
QueryResponse response = client.query(query);
//得到所有匹配文档数据
SolrDocumentList docs = response.getResults();
int Time = response.getQTime();
System.out.println("Ducument count:" + docs.getNumFound());
System.out.println("serach times:" + response.getQTime());
System.out.println("data count:"+docs.size());
System.out.println("score: "+docs.getMaxScore());
//高亮map
Map<String, Map<String, List<String>>> map1 = response.getHighlighting();
//可以根据自己的业务逻辑对匹配文档和高亮数据做处理
//也可以通过高亮对业务字段进行筛选 处理
}
}
这是基本的API查询操作,评分使用的是solr默认的评分机制,下一篇会讲解定义自己的评分规则;
新增:
/**
* 新增数据
* @throws IOException
*/
public static int addDucument(String rid,String rxgzdw,String rygzdw,String rsfzh,String rname,String rzj02,String allname) throws IOException{
int status = 0;
System.out.println("======================add doc ===================");
Collection<SolrInputDocument> docs = new ArrayList<SolrInputDocument>();
SolrInputDocument doc = new SolrInputDocument();
if(rid != null){
doc.addField("rid", rid);
}
if(rxgzdw != null){
doc.addField("rxgzdw", rxgzdw);
}
if(rygzdw != null){
doc.addField("rygzdw", rygzdw);
}
if(rsfzh != null){
doc.addField("rsfzh", rsfzh);
}
if(rname != null){
doc.addField("rname",rname );
}
if(rzj02 != null){
doc.addField("rzj02", rzj02);
}
if(allname != null){
doc.addField("allname",allname);
}
docs.add(doc);
try {
UpdateResponse rsp = client.add(docs);
System.out.println("Add doc size" + docs.size() + " result:" + rsp.getStatus() + " Qtime:" + rsp.getQTime());
UpdateResponse rspcommit = client.commit();
status = rsp.getStatus();
System.out.println("commit doc to index" + " result:" + rsp.getStatus() + " Qtime:" + rsp.getQTime());
} catch (SolrServerException e) {
e.printStackTrace();
}
return status;
}
更新:
/**
*-----------更新文档:updateDocuments()-----------
*/
public static int updateDocuments(String rid,String rxgzdw,String rygzdw,String rsfzh,String rname,String rzj02) {
int status = 1;
System.out.println("======================updateField ===================");
HashMap<String, Object> oper = new HashMap<String, Object>();
SolrInputDocument doc = new SolrInputDocument();
if(rid != null){
doc.addField("rid", rid);
}
if(rxgzdw != null){
doc.addField("rxgzdw", rxgzdw);
}
if(rygzdw != null){
doc.addField("rygzdw", rname);
}
if(rsfzh != null){
doc.addField("rsfzh", rsfzh);
}
if(rname != null){
doc.addField("rname", rygzdw);
}
if(rzj02 != null){
doc.addField("rzj02", rzj02);
}
try {
UpdateResponse rsp = client.add(doc);
System.out.println("update doc id:" + rid + " result:" + rsp.getStatus() + " Qtime:" + rsp.getQTime());
UpdateResponse rspCommit = client.commit();
status = rspCommit.getStatus();
System.out.println("commit doc to index" + " result:" + rspCommit.getStatus() + " Qtime:" + rspCommit.getQTime());
} catch (SolrServerException | IOException e) {
e.printStackTrace();
}
return status;
}
删除:
/**
* -----------删除文档BY ID:deleteById()-----------
* @param rid
*/
public static int deleteById(String rid) {
int status = 1;
System.out.println("======================deleteById ===================");
try {
UpdateResponse rsp = client.deleteById(rid);
client.commit();
status = rsp.getStatus();
System.out.println("delete id:" + rid + " result:" + rsp.getStatus() + " Qtime:" + rsp.getQTime());
} catch (SolrServerException | IOException e) {
e.printStackTrace();
}
return status;
}
》》》常规的API操作还是比较简单的,这就是增删改查的API。
下一篇讲解集群搭建: