整合篇:零基础学习与使用Solr

配套资料,免费下载
链接:https://pan.baidu.com/s/1jA217UgqXpONi_fV-aOzqw
提取码:bm2g
复制这段内容后打开百度网盘手机App,操作更方便哦

1、Solr的概述

大多数搜索引擎应用都必须具有某种搜索功能,问题是搜索功能往往是巨大的资源消耗并且它们由于沉重的数据库加载而拖垮你的应用的性能。这就是为什么转移负载到一个外部的搜索服务器是一个不错的主意,Apache Solr是一个流行的开源搜索服务器,它通过使用类似REST的HTTP API,这就确保你能从几乎任何编程语言来使用Solr。Solr是一个开源搜索平台,用于构建搜索应用程序。 它建立在Lucene(全文搜索引擎)之上。 Solr是企业级的,快速的和高度可扩展的。 使用Solr构建的应用程序非常复杂,可提供高性能。

为了在CNET网络的公司网站上添加搜索功能,Yonik Seely于2004年创建了Solr。并在2006年1月,它成为Apache软件基金会下的一个开源项目。并于2016年发布最新版本Solr 6.0,支持并行SQL查询的执行。Solr可以和Hadoop一起使用。由于Hadoop处理大量数据,Solr帮助我们从这么大的源中找到所需的信息。不仅限于搜索,Solr也可以用于存储目的。像其他NoSQL数据库一样,它是一种非关系数据存储和处理技术。总之,Solr是一个可扩展的,可部署,搜索/存储引擎,优化搜索大量以文本为中心的数据。

2、Solr的安装

下载地址:https://lucene.apache.org/solr/downloads.html

image-20210110123053018

解压Solr:我这里解压到桌面上

启动Solr:solr start

image-20210110103404258

打开Solr:http://localhost:8983/solr/

image-20210110103453870

3、Solr的命令

启动solr

  • bin/solr start -help 查看start帮助
  • bin/solr start 启动单机版
  • bin/solr start -f 前台启动
  • bin/solr start -p 8984 指定端口启动
  • bin/solr restart 重启项目,如果不能重启,请先全部关闭,然后再启动
  • bin/solr start -cloud 启动分布式版本
  • bin/solr start -e cloud -noprompt -e表示要启动一个现有的例子,例子名称是cloud,cloud这个例子是以SolrCloud方式启动的

停止solr

  • bin/solr stop -all 停止solr

查看solr状态

  • bin/solr status 查看solr状态

创建solr核心

如果是单机版要创建core,如果是分布式的要创建collection

  • bin/solr create -help 查看create帮助

    bin/solr create -c abc 创建名称为abc的核心,abc是core还是collection,取决于solr是单机版还是cloud版本

删除solr核心

  • bin/solr delete -c abc 删除一个core或collection

4、创建核心数据库

核心可以理解为数据库,而核心里边的document可以理解为表。

4.1、命令行方式

1、打开dos命令窗口,切换目录到${solr.home}\bin,然后输入:solr create -c 核心名称,我这里输入的核心名称是core1之后回车;

2、打开solr安装文件,在/server/solr下就会出现新的文件夹core1(就是新创建的core1);

3、打开浏览器,输入solr访问路径:http://localhost:8983/solr,就会看到新建的core

image-20210110104304652

4.2、图形化方式

1、直接在/server/solr下创建新文件夹,名字自定义,此处命名为core2,作为新建的core;

2、找到/server/solr/configsets/_default目录下的conf文件夹,然后拷贝一份到/server/solr/core2目录节点下。

3、然后按照下图操作:

image-20210110104749931

5、添加中文分词器

因为solr是外国人开发的,对中文的支持并不是很好,很多单词都不能解析,这时候我们需要增加中文分词器,对中文单词进行分词处理,提高搜索准确度。

5.1、添加内置分词器

(1)在solr安装文件夹下面找到这个lucene-analyzers-smartcn-8.7.0.jar包

image-20210110112926303

(2)复制一份到 solr-8.7.0\server\solr-webapp\webapp\WEB-INF\lib 这个目录下面

image-20210110113332589

(3)接下来在你的项目conf下的配置文件managed-schema最后添加以下配置,我们这里为 core1 核心进行配置

image-20210110113659073

<!-- ChineseAnalyzer 自带的中文分词器 -->
<fieldType name="text_cn" 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>

这样就配置好了类型名称是 text_cn 的分词器。

(4)重启solr服务,查看分词效果

未分词前效果:

image-20210110114710154

已分词后效果:

image-20210110122631488

5.2、添加外部分词器

(1)先下载solr8版本的ik分词器,下载地址:https://search.maven.org/search?q=com.github.magese

image-20210110115115428

(2)将下载好的jar包放入 solr-8.7.0\server\solr-webapp\webapp\WEB-INF\lib 目录中,下载速度可能会有点慢,如果下载失败,请到配套资料中获取

image-20210110121912692

(3)接下来在你的项目conf下的配置文件managed-schema最后添加以下配置,我们这里为 core1 核心进行配置

image-20210110113659073

<!-- ChineseAnalyzer 外部的中文分词器 -->
<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>

这样就配置好了类型名称是 text_ik 的分词器。

(4)重启solr服务,查看分词效果

未分词前效果:

image-20210110114710154

已分词后效果:

image-20210110122738437

6、导入外部数据

solr是一个全文检索软件,既然要进行全文检索,那肯定需要很多数据才有必要使用solr全文检索,在这里,我将要给大家介绍两种常见的数据导入。

6.1、手动导入单条的数据

打开页面:http://localhost:8983/solr/#/core1/documents

复制内容:

{
	"item_id":"40001",
	"item_title":"苹果 iPhone 12 Pro Max",
	"item_price":"12758.00",
	"item_image":"https://img.alicdn.com/imgextra/i3/1710936647/O1CN01amGTkj1yyNHgrUWAv_!!0-item_pic.jpg_430x430q90.jpg",
	"item_brand":"苹果",
	"item_category":"手机",
	"item_seller":"苹果官方旗舰店",
	"item_goods_id":"4"
}

提交内容:

image-20210110132415054

查询内容:http://localhost:8983/solr/#/core1/query

image-20210110132454271

6.2、批量导入数据库数据

6.2.1、准备数据库

打开本地的mysql数据库,执行以下代码:

DROP DATABASE IF EXISTS `test` ;

CREATE DATABASE `test` ;

USE `test` ;

DROP TABLE IF EXISTS `item` ;

CREATE TABLE `item` (
  `id` BIGINT (20) NOT NULL COMMENT '商品SKUID',
  `title` VARCHAR (64) NOT NULL COMMENT '商品标题',
  `price` DOUBLE NOT NULL COMMENT '商品价格',
  `image` VARCHAR (255) NOT NULL COMMENT '商品图片',
  `spec` VARCHAR (255) NOT NULL COMMENT '商品规格',
  `brand` VARCHAR (32) NOT NULL COMMENT '商品品牌',
  `category` VARCHAR (32) NOT NULL COMMENT '商品分类',
  `seller` VARCHAR (32) NOT NULL COMMENT '商品卖家',
  `goods_id` BIGINT (20) NOT NULL COMMENT '商品SPUID',
  `is_deleted` INT (11) NOT NULL DEFAULT '0' COMMENT '是否删除(0:不删除,1:已删除)',
  `last_modified` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间(最后一次数据修改时间)',
  PRIMARY KEY (`id`)
) ENGINE = INNODB DEFAULT CHARSET = utf8 COMMENT = '商品明细表' ;

INSERT INTO `item` (
  `id`,
  `title`,
  `price`,
  `image`,
  `spec`,
  `brand`,
  `category`,
  `seller`,
  `goods_id`,
  `is_deleted`,
  `last_modified`
) 
VALUES
  (
    10000,
    '【新品热卖中】Redmi Note 0 Pro',
    100,
    'https://img.alicdn.com/imgextra/i2/1714128138/O1CN01YOG4Ue29zFpwZ5cdD_!!1714128138.png_430x430q90.jpg',
    '{\"机身内存\":\"16G\",\"网络\":\"联通2G\"}',
    '小米',
    '手机',
    '小米官方旗舰店',
    1,
    0,
    '2021-01-10 13:50:45'
  ),
  (
    10001,
    '【新品热卖中】Redmi Note 1 Pro',
    201,
    '{\"机身内存\":\"32G\",\"网络\":\"联通3G\"}',
    '2021-01-10 13:50:49'
  ),
  (
    10002,
    '【新品热卖中】Redmi Note 2 Pro',
    302,
    '{\"机身内存\":\"64G\",\"网络\":\"联通4G\"}',
    '2021-01-10 13:50:51'
  ),
  (
    10003,
    '【新品热卖中】Redmi Note 3 Pro',
    403,\"网络\":\"联通5G\"}',
    '2021-01-10 13:50:53'
  ),
  (
    10004,
    '【新品热卖中】Redmi Note 4 Pro',
    504,
    '2021-01-10 13:50:55'
  ),
  (
    10005,
    '【新品热卖中】Redmi Note 5 Pro',
    605,
    '2021-01-10 13:50:57'
  ),
  (
    10006,
    '【新品热卖中】Redmi Note 6 Pro',
    706,
    '2021-01-10 13:51:00'
  ),
  (
    10007,
    '【新品热卖中】Redmi Note 7 Pro',
    807,
    '2021-01-10 13:51:01'
  ),
  (
    10008,
    '【新品热卖中】Redmi Note 8 Pro',
    908,
    '2021-01-10 13:51:03'
  ),
  (
    10009,
    '【新品热卖中】Redmi Note 9 Pro',
    999,
    '2021-01-10 13:51:05'
  ),
  (
    20000,
    '【回馈老用户】Mate 40 pro+',
    10499,
    'https://img.alicdn.com/imgextra/i4/2215302589/O1CN01HvJj3E1Uzo2riFgSG_!!0-item_pic.jpg_430x430q90.jpg',\"网络\":\"移动5G\"}',
    '华为',
    '华为官方旗舰店',
    2,
    '2021-01-10 13:51:07'
  ),
  (
    20001,
    '【回馈老用户】Mate 41 pro+',
    11499,
    '2021-01-10 13:51:08'
  ),
  (
    20002,
    '【回馈老用户】Mate 42 pro+',
    12499,
    '2021-01-10 13:51:11'
  ),
  (
    20003,
    '【回馈老用户】Mate 43 pro+',
    13499,
    '2021-01-10 13:51:13'
  ),
  (
    20004,
    '【回馈老用户】Mate 44 pro+',
    14499,
    '2021-01-10 13:51:14'
  ),
  (
    20005,
    '【回馈老用户】Mate 45 pro+',
    15499,
    '2021-01-10 13:51:16'
  ),
  (
    20006,
    '【回馈老用户】Mate 46 pro+',
    16499,
    '2021-01-10 13:51:17'
  ),
  (
    20007,
    '【回馈老用户】Mate 47 pro+',
    17499,
    '2021-01-10 13:51:19'
  ),
  (
    20008,
    '【回馈老用户】Mate 48 pro+',
    18499,
    '2021-01-10 13:51:21'
  ),
  (
    20009,
    '【回馈老用户】Mate 49 pro+',
    19499,
    '2021-01-10 13:51:22'
  ),
  (
    30000,
    '【高端精品机】液晶彩色电视机 50寸',
    5990,
    'https://img.alicdn.com/imgextra/i2/2616970884/O1CN01bzBHDl1IOulmPgSgp_!!2616970884.jpg_430x430q90.jpg',
    '{\"电视屏幕尺寸\":\"50英寸\"}',
    '三星',
    '电视',
    '三星官方旗舰店',
    3,
    '2021-01-10 13:51:24'
  ),
  (
    30001,
    '【高端精品机】液晶彩色电视机 51寸',
    5991,
    '{\"电视屏幕尺寸\":\"51英寸\"}',
    '2021-01-10 13:51:26'
  ),
  (
    30002,
    '【高端精品机】液晶彩色电视机 52寸',
    5992,
    '{\"电视屏幕尺寸\":\"52英寸\"}',
    '2021-01-10 13:51:27'
  ),
  (
    30003,
    '【高端精品机】液晶彩色电视机 53寸',
    5993,
    '{\"电视屏幕尺寸\":\"53英寸\"}',
    '2021-01-10 13:51:29'
  ),
  (
    30004,
    '【高端精品机】液晶彩色电视机 54寸',
    5994,
    '{\"电视屏幕尺寸\":\"54英寸\"}',
    '2021-01-10 13:51:31'
  ),
  (
    30005,
    '【高端精品机】液晶彩色电视机 55寸',
    5999,
    '{\"电视屏幕尺寸\":\"55英寸\"}',
    '2021-01-10 13:51:33'
  ),
  (
    30006,
    '【高端精品机】液晶彩色电视机 56寸',
    '{\"电视屏幕尺寸\":\"56英寸\"}',
    '2021-01-10 13:51:34'
  ),
  (
    30007,
    '【高端精品机】液晶彩色电视机 57寸',
    '{\"电视屏幕尺寸\":\"57英寸\"}',
    '2021-01-10 13:51:37'
  ),
  (
    30008,
    '【高端精品机】液晶彩色电视机 58寸',
    '{\"电视屏幕尺寸\":\"58英寸\"}',
    '2021-01-10 13:51:38'
  ),
  (
    30009,
    '【高端精品机】液晶彩色电视机 59寸',
    '{\"电视屏幕尺寸\":\"59英寸\"}',
    '2021-01-10 13:51:40'
  ) ;

image-20210110193329825

6.2.2、配置数据库

(1)编写solr和mysql的映射关系

image-20210110155757719

拷贝以下内容,直接粘贴到该文件的最后部分:(solrconfig.xml)

<requestHandler name="/dataimport" class="org.apache.solr.handler.dataimport.DataImportHandler">
  <lst name="defaults">
    <str name="config">db-data-config.xml</str>
  </lst>
</requestHandler>

创建映射配置,直接粘贴到该文件的开始部分:(db-data-config.xml)

image-20210110155909941

<?xml version="1.0" encoding="UTF-8" ?>
<dataConfig>
	<!--
		配置数据源:
		driver		:数据库驱动
		url			:数据库连接
		user		:数据库用户
		password	:数据库密码
	-->
    <dataSource driver="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/test" user="root" password="root" />
    <document>
		<!--
			配置数据表:
			name			:实体对应表名
			pk				:主键对应字段
			query			:全部导入语句
			deltaQuery		:查询出所有经过修改(通过时间判断)的记录主键id
			deletedPKQuery	:查询出所有经过删除(通过字段标记)的记录主键id
			deltaImportQuery:增量导入语句,id来源于以上两条语句,对索引库进行更新操作,可能是删除,添加,修改
		-->
        <entity 
				name="item" 
				pk="id"
				query="select * from item where is_deleted = 0"
				deltaQuery="select id from item where last_modified > '${dataimporter.last_index_time}+8'"
				deletedPkQuery="select id from item where is_deleted = 1"
				deltaImportQuery="select * from item where id = '${dataimporter.delta.id}'"
		>
			<!--
				配置数据域:
				column		:数据库中字段的名称,特别要注意,name="id"中的id才是solr内置的域名,本配置其余id均为数据库字段主键id
				name		:solr普通域的字段名
			-->
            <field column="id" name="id" />
			<field column="title" name="item_title" />
			<field column="price" name="item_price" />
			<field column="image" name="item_image" />
			<field column="brand" name="item_brand" />
			<field column="category" name="item_category" />
			<field column="seller" name="item_seller" />
			<field column="goods_id" name="item_goods_id" />
			<field column="is_deleted" name="item_is_deleted" />
			<field column="last_modified" name="item_last_modified" />		
        </entity>
    </document>
</dataConfig>

(2)拷贝solr连mysql的相关jar包

image-20210110144345127

image-20210110144456020

image-20210110144626606

6.2.3、配置普通域

属性 描述 取值 默认
stored 如果为true,该字段的实际值将在查询后显示出来 true/false true
indexed 如果为true,则可以在查询中使用该字段的值来检索匹配的文档。 true/false true
uninvertible 如果为true,则表示indexed=“true” docValues="false"在查询时字段可以“un-inverted”以构建大内存数据结构以代替DocValues。 出于历史原因,默认为true,但强烈建议用户将其设置false为稳定性并docValues="true"根据需要使用。 true/false true
docValues 如果为true,则字段的值将会放在面向列的DocValues结构中 true/false false
multiValued 如果为true,则表示单个文档可能包含此字段类型的多个值 true/false false
required 指示Solr拒绝任何添加没有此字段值的文档的尝试。此属性默认为false。 true/false false
omitNorms 如果为true,则省略与此字段关联的规范(这将禁用字段的长度规范化,并节省一些内存)。对于所有原始(未分析)字段类型,例如int,float,data,bool和string,默认为true。只有全文字段或字段需要规范。 true/false false
omitTermFreqAndPositions 如果为true,则忽略此字段的词频率,位置和有效负载。对于不需要该信息的字段,这可以提高性能。它还减少了索引所需的存储空间。依赖于使用此选项在字段上发出的位置的查询将无法查找文档。对于非文本字段的所有字段类型,此属性默认为true true/false false
omitPositions 类似omitTermFreqAndPositions但保留词频率信息 true/false false
termVectors
termPositions
termOffsets
termPayloads
这些选项指示Solr维护每个文档的完整词向量,可选地包括这些向量中每个词出现的位置,偏移和有效负载信息。这些可用于加速突出显示和其他辅助功能,但在索引大小方面施加了相当大的成本。它们对于Solr的典型用途不是必需的 true/false false
sortMissingFirst
sortMissingLast
排序结果时,Solr会列出那些排在搜索结果最前面的/最后面的,但该字段却没有取值的文档 true/false false

配置普通域,直接粘贴到该文件的最后部分:(managed-schema)

image-20210110160016189

<!--配置普通域-->
<field name="item_title" type="text_ik" indexed="true" stored="true"/>
<field name="item_price" type="pdouble" indexed="true" stored="true" docValues="false"/>
<field name="item_image" type="string" indexed="false" stored="true" />
<field name="item_brand" type="string" indexed="true" stored="true" />
<field name="item_category" type="string" indexed="true" stored="true" />
<field name="item_seller" type="text_ik" indexed="true" stored="true" />
<field name="item_goods_id" type="plong" indexed="true" stored="true" />
<field name="item_is_deleted" type="pint" indexed="true" stored="true" />
<field name="item_last_modified" type="pdate" indexed="true" stored="true" />

6.2.4、配置复制域

复制域常用于多域搜索,如:电商项目中搜索商品,既要在标题域中搜索也要在品牌域中搜索,传统的做法需要手工写两次,而solr想发送一次请求,可到两个域中搜索,为此,引入了复制域的概念,将两个域的域名复制到一个域中。

配置复制域,直接粘贴到该文件的最后部分:(managed-schema)

image-20210110160016189

<!--配置复制域-->
<field name="item_keywords" type="text_ik" indexed="true" stored="false" multiValued="true"/>
<copyField source="item_title" dest="item_keywords"/>
<copyField source="item_brand" dest="item_keywords"/>
<copyField source="item_category" dest="item_keywords"/>
<copyField source="item_seller" dest="item_keywords"/>

6.2.5、配置动态域

当我们需要动态扩充字段时,我们需要使用动态域。对于电商系统来说,规格的值是不确定的,所以我们需要使用动态域来实现。

配置动态域,直接粘贴到该文件的最后部分:(managed-schema)

image-20210110160016189

<!--配置动态域-->
<dynamicField name="item_spec_*" type="string" indexed="true" stored="true" />

6.2.6、导所有数据

(1)重启solr系统

(2)导入指定数据库中的数据(这种导入方式无法导入动态域,动态域需要手写代码实现)

全量导入:全部正常数据

solr执行:

image-20210110195030812

solr查看:

image-20210110193914490

增量导入:删除部分数据

mysql执行:

UPDATE item SET is_deleted = 1 WHERE brand = '小米';

solr执行:

image-20210110195124125

solr查看:

image-20210110194249825

增量导入:添加部分数据

mysql执行:

INSERT INTO `test`.`item` (`id`, `title`, `price`, `image`, `spec`, `brand`, `category`, `seller`, `goods_id`) 
VALUES ('40001', '苹果手机', '1999', 'apple.jpg', '{\"屏幕大小\":\"6寸\",“网络”:\"电信4G\"}', '苹果', '手机', '苹果官方旗舰店', '4');

solr执行:

image-20210110195222859

solr查看:

image-20210110194921209

7、配置安全账户

(1)打开路径:solr-8.7.0\server\etc,在此目录下新建 verify.properties 配置文件

image-20210110200507409

#用户名: 密码,权限
admin: admin,admin
user1: pass1,admin
user2: pass2,admin

(2)打开路径:solr-8.7.0\server\contexts,在文件configure中添加获取用户文件的配置,内容如下:

image-20210110200731320

<Get name="securityHandler">
	<Set name="loginService">
		<New class="org.eclipse.jetty.security.HashLoginService">
			<Set name="name">verify—name</Set>
			<Set name="config"><SystemProperty name="jetty.home" default="."/>/etc/verify.properties</Set>
		</New>
	</Set>
</Get>

(3)打开路径:solr-8.7.0\server\solr-webapp\webapp\WEB-INF

image-20210110201301722

在文件中找到security-constraint的配置,内容如下:

<!-- Get rid of error message -->
<security-constraint>
    <web-resource-collection>
        <web-resource-name>Disable TRACE</web-resource-name>
        <url-pattern>/</url-pattern>
        <http-method>TRACE</http-method>
    </web-resource-collection>
    <auth-constraint/>
</security-constraint>
<security-constraint>
    <web-resource-collection>
        <web-resource-name>Enable everything but TRACE</web-resource-name>
        <url-pattern>/</url-pattern>
        <http-method-omission>TRACE</http-method-omission>
    </web-resource-collection>
</security-constraint>

在上边这段代码下边加入以下代码用于权限校验,内容如下:

<security-constraint>
	<web-resource-collection>
		<web-resource-name>Solr Admin TRACE</web-resource-name>
		<url-pattern>/</url-pattern>
		<http-method-omission>TRACE</http-method-omission>
	</web-resource-collection>
	<auth-constraint>
		<role-name>admin</role-name>
	</auth-constraint>
    <user-data-constraint>
        <transport-guarantee>NONE</transport-guarantee>
    </user-data-constraint>	
</security-constraint>

<login-config>
	<auth-method>BASIC</auth-method>
	<realm-name>verify-name</realm-name>
</login-config>

<security-role>
    <role-name>admin</role-name>
	<description>Solr Admin</description>
</security-role>

(4)重新启动solr,访问地址:http://localhost:8983/solr/

image-20210110201958888

8、手写代码访问

8.1、创建工程

image-20210110204137989

image-20210110214956489

image-20210110215039061

image-20210110215112620

image-20210110204501017

(1)添加相关依赖

<properties>
    <java.version>1.8</java.version>
    <mysql.version>5.1.49</mysql.version>
</properties>

...

<dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.75</version>
</dependency>

(2)添加相关配置

spring:
  data:
    solr:
      host: http://user1:pass1@localhost:8983/solr
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/test
    username: root
    password: root

(3)配置实体对象(solr与实体之间的关系)

com.caochenlei.integrationsolr.entity.Item

@Data
public class Item implements Serializable {
    @Field("id")
    private Long id;
    @Field("item_title")
    private String title;
    @Field("item_price")
    private Double price;
    @Field("item_image")
    private String image;
    @Dynamic
    @Field("item_spec_*")
    private Map<String, String> spec;
    @Field("item_brand")
    private String brand;
    @Field("item_category")
    private String category;
    @Field("item_seller")
    private String seller;
    @Field("item_goods_id")
    private Long goodsId;
    @Field("item_is_deleted")
    private Integer isDeleted;
    @Field("item_last_modified")
    private Date lastModified;
}

(4)新建配置对象(solrClient需要重新设置)

com.caochenlei.integrationsolr.config.SolrTemplateConfig

@Component
public class SolrTemplateConfig {
    @Bean
    public HttpSolrClient solrClient(SolrProperties solrProperties) {
        HttpClient httpClient = new SystemDefaultHttpClient();
        return new HttpSolrClient.Builder(solrProperties.getHost()).withHttpClient(httpClient).build();
    }

    @Bean
    public SolrTemplate solrTemplate(SolrClient solrClient) {
        return new SolrTemplate(solrClient);
    }
}

(5)注入模板对象

com.caochenlei.integrationsolr.IntegrationSolrApplicationTests

@SpringBootTest
class IntegrationSolrApplicationTests {
    @Autowired
    private SolrTemplate solrTemplate;
    
    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    //核心名称
    private static final String CORE_NAME = "core1";
}

8.2、删除全部数据

@Test
void testDeleteAll() throws Exception {
    SimpleQuery query = new SimpleQuery("*:*");
    solrTemplate.delete(CORE_NAME, query);
    solrTemplate.commit(CORE_NAME);
}

8.3、添加一条数据

@Test
void testAdd() throws Exception {
    //添加动态域内容,Solr7之后版本的动态域,不能使用中文作为拼接索引
    Map<String, String> spec = new HashMap<String, String>();
    spec.put(URLEncoder.encode("屏幕尺寸", "UTF-8"), "19寸");
    spec.put(URLEncoder.encode("内存大小", "16G");

    Item item = new Item();
    item.setId(50001L);
    item.setTitle("外星人笔记本");
    item.setPrice(19999.00);
    item.setImage("alien.jpg");
    item.setSpec(spec);
    item.setBrand("外星人");
    item.setCategory("笔记本");
    item.setSeller("外星人官方旗舰店");
    item.setGoodsId(5L);
    item.setIsDeleted(0);
    item.setLastModified(new Date());

    solrTemplate.saveBean(CORE_NAME, item);
    solrTemplate.commit(CORE_NAME);
}

8.4、查询一条数据

@Test
void testGetById() throws Exception {
    Optional<Item> itemOptional = solrTemplate.getById(CORE_NAME, 50001L, Item.class);
    Item item = itemOptional.get();
    System.out.println(item.getId());
    System.out.println(item.getTitle());
    System.out.println(item.getPrice());
    System.out.println(item.getImage());

    Map<String, String> spec = item.getSpec();
    Set<Map.Entry<String, String>> specEntries = spec.entrySet();
    for (Map.Entry<String, String> specEntry : specEntries) {
        String specName = specEntry.getKey().replace("_","%");
        String specValue = specEntry.getValue();
        System.out.println(URLDecoder.decode(specName, "UTF-8") + ":" + specValue);
    }

    System.out.println(item.getBrand());
    System.out.println(item.getCategory());
    System.out.println(item.getSeller());
    System.out.println(item.getGoodsId());
    System.out.println(item.getIsDeleted());
    System.out.println(item.getLastModified());
}

8.5、修改一条数据

@Test
void testUpdate() throws Exception {
    //添加动态域内容,Solr7之后版本的动态域,不能使用中文作为拼接索引
    Map<String, "16G");

    Item item = new Item();
    item.setId(50001L);
    item.setTitle("外星人电视机");
    item.setPrice(19999.00);
    item.setImage("alien.jpg");
    item.setSpec(spec);
    item.setBrand("外星人");
    item.setCategory("电视机");
    item.setSeller("外星人官方旗舰店");
    item.setGoodsId(5L);
    item.setIsDeleted(0);
    item.setLastModified(new Date());

    solrTemplate.saveBean(CORE_NAME, item);
    solrTemplate.commit(CORE_NAME);
}

8.6、删除一条数据

@Test
void testDeleteById() throws Exception {
    solrTemplate.deleteByIds(CORE_NAME, "50001");
    solrTemplate.commit(CORE_NAME);
}

8.7、导入全部数据

@Test
void testImportAll() throws Exception {
    //查询出所有数据
    String sql = "select * from item where is_deleted = 0";
    List<Item> items = jdbcTemplate.query(sql, new RowMapper<Item>() {
        @Override
        public Item mapRow(ResultSet resultSet, int i) {
            Item item = new Item();
            try {
                item.setId(resultSet.getLong("id"));
                item.setTitle(resultSet.getString("title"));
                item.setPrice(resultSet.getDouble("price"));
                item.setImage(resultSet.getString("image"));

                Map<String, String>();
                String specJSON = resultSet.getString("spec");
                Map specMap = JSON.parseObject(specJSON);
                Set<Map.Entry<String, String>> specEntries = specMap.entrySet();
                for (Map.Entry<String, String> specEntry : specEntries) {
                    String specName = URLEncoder.encode(specEntry.getKey(), "UTF-8");
                    String specValue = specEntry.getValue();
                    spec.put(specName, specValue);
                }
                item.setSpec(spec);

                item.setBrand(resultSet.getString("brand"));
                item.setCategory(resultSet.getString("category"));
                item.setSeller(resultSet.getString("seller"));
                item.setGoodsId(resultSet.getLong("goods_id"));
                item.setIsDeleted(resultSet.getInt("is_deleted"));
                item.setLastModified(resultSet.getDate("last_modified"));
            } catch (Exception e) { e.printStackTrace(); }
            return item;
        }
    });

    //导入所有数据
    solrTemplate.saveBeans(CORE_NAME, items);
    solrTemplate.commit(CORE_NAME);
}

8.8、分页查询数据

@Test
void testGetByPage() throws Exception {
    int pageCurr = 1;
    int pageSize = 20;

    SimpleQuery query = new SimpleQuery("*:*");
    query.setOffset(Long.valueOf((pageCurr - 1) * pageSize));
    query.setRows(pageSize);
    ScoredPage<Item> items = solrTemplate.queryForPage(CORE_NAME, query, Item.class);
    System.out.println("总页数:" + items.getTotalPages());
    System.out.println("总记录:" + items.getTotalElements());
    for (Item item : items) {
        System.out.println(item);
    }
}

8.9、条件查询数据

@Test
void testGetByCriteria() throws Exception {
    int pageCurr = 1;
    int pageSize = 20;

    SimpleQuery query = new SimpleQuery("*:*");
    query.setOffset(Long.valueOf((pageCurr - 1) * pageSize));
    query.setRows(pageSize);

    Criteria criteria = new Criteria("item_title").contains("Pro");
    criteria = criteria.and("item_price").greaterThanEqual(15000);
    criteria = criteria.and("item_price").lessThanEqual(18000);
    query.addCriteria(criteria);

    ScoredPage<Item> items = solrTemplate.queryForPage(CORE_NAME, Item.class);
    System.out.println("总页数:" + items.getTotalPages());
    System.out.println("总记录:" + items.getTotalElements());
    for (Item item : items) {
        System.out.println(item);
    }
}

8.10、排序查询数据

@Test
void testGetBySort() throws Exception {
    int pageCurr = 1;
    int pageSize = 20;

    SimpleQuery query = new SimpleQuery("*:*");
    query.setOffset(Long.valueOf((pageCurr - 1) * pageSize));
    query.setRows(pageSize);

    query.addSort(Sort.by(Sort.Direction.DESC, "item_goods_id"));

    ScoredPage<Item> items = solrTemplate.queryForPage(CORE_NAME, Item.class);
    System.out.println("总页数:" + items.getTotalPages());
    System.out.println("总记录:" + items.getTotalElements());
    for (Item item : items) {
        System.out.println(item);
    }
}

8.11、高亮查询数据

@Test
void testGetByHighlight() throws Exception {
    int pageCurr = 1;
    int pageSize = 20;

    SimpleHighlightQuery query = new SimpleHighlightQuery();
    query.setOffset(Long.valueOf((pageCurr - 1) * pageSize));
    query.setRows(pageSize);

    //设置高亮选项
    HighlightOptions highlightOptions = new HighlightOptions();
    highlightOptions.setSimplePrefix("<em style='color:red'>");
    highlightOptions.setSimplePostfix("</em>");
    query.setHighlightOptions(highlightOptions);

    //设置搜索条件
    Criteria criteria = new Criteria("item_keywords").contains("华为");
    query.addCriteria(criteria);

    HighlightPage<Item> items = solrTemplate.queryForHighlightPage(CORE_NAME, Item.class);
    System.out.println("总页数:" + items.getTotalPages());
    System.out.println("总记录:" + items.getTotalElements());

    //获取高亮入口
    List<HighlightEntry<Item>> highlighted = items.getHighlighted();
    for (HighlightEntry<Item> itemHighlightEntry : highlighted) {
        //获取原来对象
        Item item = itemHighlightEntry.getEntity();
        //获取高亮集合
        List<HighlightEntry.Highlight> highlights = itemHighlightEntry.getHighlights();
        for (HighlightEntry.Highlight highlight : highlights) {
            //获取高亮域
            Field field = highlight.getField();
            //域可能多值
            List<String> snipplets = highlight.getSnipplets();
            for (String snipplet : snipplets) {
                if ("item_title".equals(field.getName())) {
                    item.setTitle(snipplet);
                }
                if ("item_brand".equals(field.getName())) {
                    item.setBrand(snipplet);
                }
                if ("item_category".equals(field.getName())) {
                    item.setCategory(snipplet);
                }
                if ("item_seller".equals(field.getName())) {
                    item.setSeller(snipplet);
                }
            }
        }
        //输出高亮对象
        System.out.println(item);
    }
}

相关文章

Nacos 中的参数有很多,如:命名空间、分组名、服务名、保护...
Nacos 支持两种 HTTP 服务请求,一个是 REST Template,另一...
Nacos 是 Spring Cloud Alibaba 中一个重要的组成部分,它提...
Spring Cloud Alibaba 是阿里巴巴提供的一站式微服务开发解决...
在 Nacos 的路由策略中有 3 个比较重要的内容:权重、保护阈...
前两天遇到了一个问题,Nacos 中的永久服务删除不了,折腾了...