网页右边,向下滑有目录索引,可以根据标题跳转到你想看的内容 如果右边没有就找找左边
Solr是基于Apache Lucene构建的用于搜索和分析的开源解决方案。可提供可扩展索引、搜索功能、高亮显示和文件解析功能 Solr本质上就是一个java web项目,且内嵌了Jetty服务器,安装起来非常方便,客户端操作Solr的过程和平时我们所写项目一样,请求Solr中控制器(Controller),处理完数据后把结果响应给客户端 在海量数据下,对MySql或Oracle进行模糊查询或条件查询效率很低,而搜索功能在绝大多数项目中都是必须的,如何提升搜索效率是很多互联网项目必须要考虑的问题 因为关系型数据库搜索效率低,那么直接用专用的搜索工具搜索,提升搜索效率就好了。Solr就是一个这样的工具
基于Apache Lucene(全文检索工具库)实现搜索。但是Lucene的使用对于绝大多数的程序员都是噩梦级的 基于谷歌API实现搜索 基于百度API实现搜索
正向索引:从文档内容到词组的过程,每次搜索需要搜索所有文档,每个文档比较搜索条件和词组(文档 i am a chinese 词组i,am,a,chinese),就好比想要找对计算机有兴趣的人,找的时候,先把所有人的喜好问一遍,然后让喜好计算机的人跟我走 反向索引:是正向索引的逆向。建立词组和文档的映射关系。通过找到词组就能找到文档内容(和新华字典找字很像),找对计算机有兴趣的人,直接先问,谁对计算机有兴趣,然后针对这些人寻找符合条件的
Solr能够提升检索效率的主要原因是分词和索引(反向索引,通过)
分词:会对搜索条件/存储内容进行分词,分成日常所使用的词语。 索引:存储在Solr中的内容会按照程序员的要求,决定是否建立索引,如果要求建立索引,那么会为存储内容中关键字(分词)建立索引
Solr想要给内容建立索引,Solr就必须具备数据存储能力,所有需要被搜索的内容都得存储在Solr中,在开发中需要把数据库中的数据添加到Solr中进行初始化,每次修改数据库中数据还需要同步Solr中的数据。 Solr中数据存储是存储在Document对象中,对象中可以包含的属性和属性类型都定义在scheme.xml中。如果需要自定义属性或自定义属性类型都需要修改scheme.xml配置文件。从Solr5开始schema.xml改名为managed-scheme(没有扩展名)
一、单机版环境搭建
下载地址:https://solr.apache.org/downloads.html 下载 传输到Linux并解压安装 复制解压后的包到/usr/local下
cd / usr/ local/ solr/ bin
vim solr. in. sh
修改启动参数,否则启动时报警告。提示设置SOLR_ULIMIT_CHECKD=false
. /solr start - force
Dashboard :面板显示Solr的总体信息Logging :日志Core Admin :Solr的核心。类似于数据的DatabaseJava Perperties :所有java相关属性Thread Dump :线程相关信息如果有Core,将显示在此处
二、使用步骤和细节
1. 新建核心
Solr 安装完成后默认是没有核心的,需要手动配置 需要在solr/server/solr下新建文件夹,并给定配置文件,否则无法建立
1. Linux中在/usr/local/solr-8.9.0/server/solr中新建自定义名称目录,此处示例为testcore
cd / usr/ local/ solr- 8.9 .0 / server/ solr
mkdir testcore
2.复制配置文件(在第一步内个solr文件夹中有一个configsets里面包含了default和sample_techproducts_configs.里面都是配置文件示例。default属于默认配置,较为纯净。另外一个自带了一些配置示例)
cp - r configsets/ _default/ conf/ testcore/
3. 可视化管理界面中,编写信息然后点击Add Core,等待创建成功即可
2. Analysis分词
在Solr可视化管理界面中,Core管理菜单项中都会有Analysis。表示根据Schema.xml(Managed-schema)中配置要求进行解析
当我们采用中文时,分词会按照汉字一个一个拆分,这样是不好的,我们希望按照词组分词
所以我们需要第三方类库ik-analyzer.jar来实现中文分词(上传ik-analyzer.jar到webapps中)
下载对应版本ik-analyzer.jar
下载地址:https://search.maven.org/?q=com.github.magese
上传jar包到/usr/local/solr-8.9.0/server/solr-webapp/webapp/WEB-INF/lib/ 修改指定核心的配置文件,这里修改testcore的vim /usr/local/solr-8.9.0/server/solr/testcore/conf/managed-schema
为什么要修改呢,参考我们前面分词,使用的是_test_属性来分词,那么这个属性满足不了我们的要求,所以,我们要在配置文件中配置一个新的属性,专门用来做中文分词
< field name= "myfield" type= "text_ik" indexed= "true" stored= "true" / >
< fieldType name= "text_ik" class = "solr.TextField" >
< analyzer type= "index" >
< tokenizer class = "org.wltea.analyzer.lucene.IKTokenizerFactory" useSmart= "false" conf= "ik.conf" / >
< filter class = "solr.LowerCaseFilterFactory" / >
< / analyzer>
< analyzer type= "query" >
< tokenizer class = "org.wltea.analyzer.lucene.IKTokenizerFactory" useSmart= "true" conf= "ik.conf" / >
< filter class = "solr.LowerCaseFilterFactory" / >
< / analyzer>
< / fieldType>
重启
cd / usr/ local/ solr- 8.9 .0 / bin/
. /solr stop - all
. /solr start - force
测试
3. managed-schema配置解析
<fieldType/ > :表示定义一个属性类型。在Solr中属性类型都是自定义的。在上面配置中name="text_ik"为自定义类型。当某个属性取值为text_ik是IK Analyzer才能生效<field/ > :表示想Document中添加一个属性,常用属性如下:
name
:属性名type
:属性类型indexed
:是否建立索引stored
:solr是否把该属性值响应给搜索用户required
:该属性是否是必须的。默认id是必须的multiValued
:如果为true,表示该属性为复合属性,此属性中包含了多个其他的属性。常用在多个列作为搜索条件时,把这些列定义成一个新的复合属性,通过搜索一个复合属性就可以实现搜索多个列。当设置为true时与< copyField source="" dest=""/>结合使用 < uniqueKey > :唯一主键,Solr中默认定义id属性为唯一主键。ID的值是不允许重复的。< dynamicField > :名称中允许*进行通配。代表满足特定名称要求的一组属性。
4. Dataimport快速导入
可以使用Solr自带的Dataimport功能把数据库中数据快速导入到solr中 必须保证managed-schema和数据库中表的列对应
保证managed-schema和数据库中表的列对应
< ! -- 与数据库对应,name是手机名,需要分词则type= text_ik,分词就得用索引,indexed= true ,同时需要显示stored= true -- >
< field name= "name" type= "text_ik" indexed= "true" stored= "true" / >
< ! -- price 是价格,无需分词,所以类型用pdouble,不分词就无需索引indexed= false ,需要显示stored= true -- >
< field name= "price" type= "pdouble" indexed= "false" stored= "true" / >
修改配置文件,修改solrconfig.xml添加如下内容:
< ! -- 配置数据导入的处理器 -- >
< requestHandler name= "/dataimport" class = "org.apache.solr.handler.dataimport.DataImportHandler" >
< lst name= "defaults" >
< ! -- 加载data- config. xml,需要我们自己建立-- >
< str name= "config" > data- config. xml< / str>
< / lst>
< / requestHandler>
新建data-config.xml配置文件
< ? xml version= "1.0" encoding= "UTF-8" ? >
< dataConfig>
< dataSource name= "jdbcDataSource" type= "JdbcDataSource"
driver= "com.mysql.cj.jdbc.Driver"
url= "jdbc:mysql://你的本机ip地址:3306/dubbo_demo?serverTimezone=UTC"
user= "root" password= "123456" / >
< document>
< entity dataSource= "jdbcDataSource" name= "produce"
query= "select * from t_product" >
< ! --
数据库的列和索引库的字段的映射
column 指定数据库的列名
name 指定索引库的字段名,必须和schema. xml中定义的一样
-- >
< field column= "id" name= "id" > < / field>
< field column= "name" name= "name" > < / field>
< field column= "price" name= "price" > < / field>
< / entity>
< / document>
< / dataConfig>
导入第三方jar包(两个dataimport的包,在solr安装目录下dest文件夹中,还有一个数据库驱动jar包需要我们自己引入)
cp - R solr- dataimporthandler- 8.9 .0 . jar solr- dataimporthandler- extras- 8.9 .0 . jar / usr/ local/ solr- 8.9 .0 / server/ solr- webapp/ webapp/ WEB- INF/ lib/
重启测试
5. Document菜单讲解(增删改)
1. 新增/修改(当id不存在时,新增,存在时,修改)
< doc>
< field name= "id" > 6 < / field>
< field name= "name" > 华为Mate40Pro < / field>
< field name= "price" > 8900 < / field>
< / doc>
< delete>
< id> 6 < / id>
< / delete>
< delete>
< query> *:*</ query>
</ delete>
6. Query菜单讲解
不属于分词的条件,比如name中含有数字2的,如果数据中没有分词条件为2的,该怎么检索出数据呢?
三、使用java客户端api:SolrJ操作Solr
< dependencies>
< dependency>
< groupId> org. apache. solr< / groupId>
< artifactId> solr- solrj< / artifactId>
< version> 8.9 .0 < / version>
< / dependency>
< dependency>
< groupId> junit< / groupId>
< artifactId> junit< / artifactId>
< version> 4.12 < / version>
< / dependency>
< / dependencies>
import org. apache. solr. client. solrj. impl. HttpSolrClient ;
import org. apache. solr. common. SolrInputDocument ;
import org. junit. Test ;
import java. io. IOException ;
public class SolrTest {
@Test
public void testAddAndUpdate ( ) {
String url = "http://192.168.10.105:8983/solr/testcore" ;
HttpSolrClient solrClient = null ;
try {
solrClient = new HttpSolrClient. Builder ( url) . build ( ) ;
SolrInputDocument inputDocument = new SolrInputDocument ( ) ;
inputDocument. addField ( "id" , 5 ) ;
inputDocument. addField ( "name" , "小米11pro" ) ;
inputDocument. addField ( "price" , 3999 ) ;
solrClient. add ( inputDocument) ;
solrClient. commit ( ) ;
} catch ( Exception e) {
e. printStackTrace ( ) ;
} finally {
try {
solrClient. close ( ) ;
} catch ( IOException e) {
e. printStackTrace ( ) ;
}
}
}
}
@Test
public void testDelete ( ) {
String url = "http://192.168.10.105:8983/solr/testcore" ;
try {
HttpSolrClient solrClient = new HttpSolrClient. Builder ( url) . build ( ) ;
solrClient. deleteById ( "6" ) ;
solrClient. commit ( ) ;
} catch ( Exception e) {
e. printStackTrace ( ) ;
}
}
@Test
public void testQuery ( ) {
String url = "http://192.168.10.105:8983/solr/testcore" ;
try {
HttpSolrClient solrClient = new HttpSolrClient. Builder ( url) . build ( ) ;
SolrQuery params = new SolrQuery ( ) ;
params. setQuery ( "name:12" ) ;
params. setSort ( "price" , SolrQuery . ORDER. desc) ;
params. setStart ( 0 ) ;
params. setRows ( 5 ) ;
params. setHighlight ( true ) ;
params. addHighlightField ( "name" ) ;
params. setHighlightSimplePre ( "<span color='red'>" ) ;
params. setHighlightSimplePost ( "</span>" ) ;
QueryResponse response = solrClient. query ( params) ;
SolrDocumentList results = response. getResults ( ) ;
Map < String , Map < String , List < String > > > highlighting = response. getHighlighting ( ) ;
System . out. println ( "查询结果总条数:" + results. getNumFound ( ) ) ;
for ( SolrDocument sd: results) {
System . out. print ( sd. get ( "id" ) + " " ) ;
Map < String , List < String > > map = highlighting. get ( sd. get ( "id" ) ) ;
List < String > name = map. get ( "name" ) ;
if ( name != null && name. size ( ) > 0 ) {
System . out. println ( name. get ( 0 ) + " " + sd. get ( "price" ) ) ;
} else {
System . out. println ( sd. get ( "name" ) + " " + sd. get ( "price" ) ) ;
}
}
} catch ( Exception e) {
e. printStackTrace ( ) ;
}
}
四、Spring Data for Apache Solr
Spring Data 是 Spring的顶级项目。里面包含了N多个二级子项目,每个子项目对应一种技术或工具。其目的为了让数据访问更加简单,更加方便的和Spring进行整合。 Spring Data 项目如果单独使用时还需要配置XML配置文件的,党和Spring Boot整合使用起来非常方便。spring-boot-starter-data-xx就是对应的启动器。
引入依赖
< parent>
< groupId> org. springframework. boot< / groupId>
< artifactId> spring- boot- starter- parent< / artifactId>
< version> 2.1 .10 . RELEASE< / version>
< / parent>
< dependencies>
< dependency>
< groupId> org. springframework. boot< / groupId>
< artifactId> spring- boot- starter- web< / artifactId>
< / dependency>
< dependency>
< groupId> org. springframework. boot< / groupId>
< artifactId> spring- boot- starter- test< / artifactId>
< / dependency>
< ! -- spring boot data 封装了solrJ 的jar包-- >
< dependency>
< groupId> org. springframework. boot< / groupId>
< artifactId> spring- boot- starter- data- solr< / artifactId>
< / dependency>
< / dependencies>
编写启动类 编写配置文件(指定solr的url,但是和SolrJ不同,这里不指定核心)
spring :
data :
solr :
host : http: //192.168.10.105: 8983/solr
创建测试类 创建实体类,属性需要@Field注解标注,注意注解是solr提供的,并且要生成get、set、和toString方法
1. 添加或修改数据
方法1:属性写死到代码中,和SolrJ一样,此方法可以同时添加或修改数据
import com. yzpnb. solr. SolrApplication ;
import org. apache. solr. common. SolrInputDocument ;
import org. junit. Test ;
import org. junit. runner. RunWith ;
import org. springframework. beans. factory. annotation. Autowired ;
import org. springframework. boot. test. context. SpringBootTest ;
import org. springframework. data. solr. core. SolrTemplate ;
import org. springframework. test. context. junit4. SpringJUnit4ClassRunner ;
@RunWith ( SpringJUnit4ClassRunner . class )
@SpringBootTest ( classes = SolrApplication . class )
public class SpringDataSolrTest {
@Autowired
private SolrTemplate solrTemplate;
@Test
public void testInsert ( ) {
SolrInputDocument inputDocument = new SolrInputDocument ( ) ;
inputDocument. addField ( "id" , "6" ) ;
inputDocument. addField ( "name" , "HUAWEI-Mate40Pro" ) ;
inputDocument. addField ( "price" , "7999" ) ;
solrTemplate. saveDocument ( "testcore" , inputDocument) ;
solrTemplate. commit ( "testcore" ) ;
}
}
通过saveBean添加或修改一条数据
@Test
public void testInsert ( ) {
Product product = new Product ( ) ;
product. setId ( "8" ) ;
product. setName ( "小米10pro" ) ;
product. setPrice ( 3999d ) ;
solrTemplate. saveBean ( "testcore" , product) ;
solrTemplate. commit ( "testcore" ) ;
}
通过saveBeans() 使用List 添加多条数据(注意
,此方法只能用于添加,不能用于修改)
@Test
public void testInsert ( ) {
Product product = new Product ( ) ;
product. setId ( "8" ) ;
product. setName ( "小米10proChange" ) ;
product. setPrice ( 3999d ) ;
Product product2 = new Product ( ) ;
product. setId ( "9" ) ;
product. setName ( "小米10proChangeTwo" ) ;
product. setPrice ( 3999d ) ;
List < Product > list = new ArrayList < > ( ) ;
list. add ( product) ;
list. add ( product2) ;
solrTemplate. saveBeans ( "testcore" , list) ;
solrTemplate. commit ( "testcore" ) ;
}
2. 删除
@Test
public void testDelete ( ) {
solrTemplate. deleteByIds ( "testcore" , "d60f5f5d-de98-4d9d-bd5d-50a55f573ce5" ) ;
solrTemplate. commit ( "testcore" ) ;
}
3. 查询
@Test
public void query ( ) {
SimpleQuery query = new SimpleQuery ( ) ;
Criteria c = new Criteria ( "name" ) ;
c. is ( "12" ) ;
query. addCriteria ( c) ;
query. setOffset ( 0L ) ;
query. setRows ( 1 ) ;
ScoredPage < Product > sp = solrTemplate. queryForPage ( "testcore" , query, Product . class ) ;
System . out. println ( sp. getContent ( ) ) ;
}
@Test
public void queryHl ( ) {
ArrayList < Product > listResult = new ArrayList < > ( ) ;
SimpleHighlightQuery query = new SimpleHighlightQuery ( ) ;
Criteria c = new Criteria ( "name" ) ;
c. is ( "12" ) ;
query. addCriteria ( c) ;
query. setOffset ( 0L ) ;
query. setRows ( 10 ) ;
Sort sort = new Sort ( Sort. Direction . DESC, "id" ) ;
query. addSort ( sort) ;
HighlightOptions hlo = new HighlightOptions ( ) ;
hlo. addField ( "name" ) ;
hlo. setSimplePrefix ( "<span style='color:red;'>" ) ;
hlo. setSimplePostfix ( "</span>" ) ;
query. setHighlightOptions ( hlo) ;
HighlightPage < Product > h1 = solrTemplate. queryForHighlightPage ( "testcore" , query, Product . class ) ;
List < HighlightEntry < Product > > highlighted = h1. getHighlighted ( ) ;
for ( HighlightEntry < Product > hle: highlighted) {
List < HighlightEntry. Highlight > list = hle. getHighlights ( ) ;
Product product = hle. getEntity ( ) ;
for ( HighlightEntry. Highlight h: list) {
if ( h. getField ( ) . getName ( ) . equals ( "name" ) ) {
product. setName ( h. getSnipplets ( ) . get ( 0 ) ) ;
}
}
listResult. add ( product) ;
}
System . out. println ( listResult) ;
}
五、使用zookeeper管理solr集群
当我们拥有海量数据,一个solr肯定不够,那么就需要SolrCloud集群来多台solr协调工作,想要搭建SolrCloud,就需要先搭建zookeeper管理solr集群
1. 搭建集群环境
1. 将我们安装好的zookeeper复制到/usr/local/zookeeper下并重命名zk1
cp -r /opt/module/apache-zookeeper-3.5.9-bin/ /usr/local/zookeeper/zk1
2. 在zk1下新建data目录,data下新建文件myid,里面写上1
3. 进入zk1/conf下吧zoo_sample.cfg复制一份叫zoo.cfg(具体在上面给出的zookeeper博客中有讲到),然后修改zoo.cfg文件dataDIR为你刚创建的data目录路径
server.1中的1是myid的内容 2688 2689 2690是zookeeper内部端口 3888 3889 3890 是哦leader端口
5. 把zk1复制两份,分别叫做zk2和zk3,并修改myid的值为2,3
6. 修改zk2和zk3的zoo.cfg中dataDIR和clientPort,保证clientPort不冲突
2. 启动集群
六、SolrCloud,借助zookeeper调度的Solr集群
Solr可以搭载具备容错能力和高可用的Solr集群,集群中集群配置、自动负载均衡和查询故障转移、Zookeeper集群实现集群协调管理,这些全部功能统称为SolrCloud。 SolrCloud是基于Zookeeper进行管理的。在Solr中已经内置了Zookeeper相关内容,当执行集群创建命令会自动创建Zookeeper相关内容。这个使用的是Zookeeper的机器管理功能实现的。
1. 搭建
创建:SolrCloud已经包含在了Solr中,可以直接启动Solr集群 默认创建两个集群,端口默认第一个8983,第二个7574,每个集群默认一个主结点,一个从结点,默认创建两个核心,默认使用配置文件为纯净版的,没有示例配置的配置文件
./solr -e cloud -noprompt -force
搭建成功之后,就和单机版使用一样了,但是因为是新的项目,和单机版数据是没关联的,所以,单机版的属性配置,对接数据库,都需要你单独在集群配置,操作步骤和单机版完全相同
唯一和单机版不同的地方就是,java访问客户端时,配置文件需要更改
2. 停止命令
./solr stop -all
3. 重新运行
注意,重新运行和创建不一样
./solr start -c -p 8983 -s .. /example/cloud/node1/solr/ -force
./solr start -c -p 7574 -z localhost:9983 -s .. /example/cloud/node2/solr/ -force