列表是一个接一个显示条目的首选方式,而不是使用<br>标记。完整的列表定义包括开始和结束标记,以及表示列表中每个条目的标记。
有三种类型的列表:有序列表、无序列表和定义列表。
无序列表是一个带条目符号的列表,类似于菜单。
无序列表 - <ul> ... </ul>
ul标记定义无序列表的开始和结束,列表项包含在ul标记中。
无序列表项 - <li> ... </li>
li标记添加每个条目的文本,每个列表项必须有自己的li标记。
符号类型 <ul type="disc | circle | square">
默认情况下,浏览器将显示圆形条目符号。这可以通过使用ul标记的type属性来更改,这将更改整个列表的条目符号类型。
条目符号类型 <li type="?">
通过设置li标记的type属性,可以为列表中的某个条目设置不同的符号类型。
以下是无序列表的示例:
浏览器显示内容如下所示:
对海量数据渲染,即使是强大的 Vue 也难免会遇到性能瓶颈,卡顿、掉帧等问题接踵而至。今天,我们就来聊聊如何利用虚拟列表这一“黑科技”,解决 Vue 中万级数据列表的勾选卡顿问题,让你的列表性能飞起来!
当数据量达到上万条甚至更多时,传统的列表渲染方式会将所有数据一次性加载并渲染到页面上,这会带来一系列问题:
虚拟列表的核心思想是:只渲染可视区域内的数据,非可视区域的数据不进行渲染,从而大大减少 DOM 节点数量,提高渲染效率。
<template>
<div class="virtual-list" @scroll="handleScroll">
<div class="list-viewport" :style="{ height: `${viewportHeight}px` }">
<div class="list-container" :style="{ transform: `translateY(${startIndex * itemHeight}px)` }">
<div v-for="(item, index) in visibleData" :key="index" class="list-item" :style="{ height: `${itemHeight}px` }">
<input type="checkbox" v-model="item.checked">
{{ item.label }}
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
dataList: [], // 所有数据
visibleData: [], // 可视区域数据
viewportHeight: 0, // 可视区域高度
itemHeight: 50, // 每个列表项高度
startIndex: 0, // 起始索引
endIndex: 0, // 结束索引
};
},
mounted() {
this.viewportHeight = this.$el.clientHeight;
this.generateData(10000); // 生成 10000 条数据
},
methods: {
// 生成模拟数据
generateData(count) {
for (let i = 0; i < count; i++) {
this.dataList.push({
label: `Item ${i}`,
checked: false,
});
}
this.updateVisibleData();
},
// 更新可视区域数据
updateVisibleData() {
this.startIndex = Math.floor(this.$el.scrollTop / this.itemHeight);
this.endIndex = Math.min(this.startIndex + Math.ceil(this.viewportHeight / this.itemHeight) + 1, this.dataList.length);
this.visibleData = this.dataList.slice(this.startIndex, this.endIndex);
},
// 处理滚动事件
handleScroll() {
this.updateVisibleData();
},
},
};
</script>
虚拟列表是解决海量数据渲染性能问题的利器,使用虚拟列表可以显著提高列表的渲染效率和用户体验。在 Vue 项目中,我们可以借助虚拟列表组件或自行实现虚拟列表逻辑,优化列表性能,打造丝滑流畅的用户体验!
#头条创作挑战赛#
质文章,及时送达
作者:JasonGofen
链接:https://www.jianshu.com/p/95869ade37b3
本文内容主要讲解Solr 7.7.1 环境搭建后使用Spring boot 2.1.3集成SolrJ实现简易全文检索微服务,对于Solr与Spring boot的介绍内容网上资料很多,本文不再赘述。
关于本文内容所涉及资源在最后会给大家统一都列出来。
Spring boot 结合 SolrJ 实现对Solr Server的访问是非常简单的,它们相互之间的关系如下图所示。
主体实现是通过在Spring boot微服务中集成SolrJ,配置好Solr Server参数,调用SolrJ中的CRUD API实现请求Solr Server端进行添加、修改、删除索引和查询的操作。至于如何结合现有业务系统,我们后面介绍。
图1 简易环境说明
下面以最简单快速的方式实现全文检索基础CRUD功能。
因自己的电脑硬盘空间满了没装Linux虚拟机,就以Windows为例安装Solr Server端了。其实总体而言两个系统对Solr Server端的操作类似,各位看官举一反三就好,就两种系统部署Solr的不同下面也会做相应的提及。
已配置好的Solr 7.7.1下载:
https://pan.baidu.com/s/11s18oJVKpEVc-AmZO1xkgA
我们首先来了解一下Solr的常见命令:
启动:
./solr start
关闭:
./solr stop -all
重启:
./solr restart
创建Core:
./solr create -c YourCoreName -d _default
删除Core:
./solr delete -c YourCoreName
关于Solr更细致的内容,大家可以参阅下方链接:
Solr 官网
https://lucene.apache.org/solr/
Solr API官方文档
http://lucene.apache.org/solr/7_7_1/solr-solrj/index.html
Solr 中文文档(译版)
https://www.w3cschool.cn/solr_doc/solr_doc-t3642fkr.html
要想搭建Solr Server拢共分3步:
步骤1-1:下载安装JDK和Solr Server端
下载安装JDK 8:JDK的安装在这就不说了,网上有很多资料。\
Java SE Development Kit 8 下载
下载Solr 7.7.1压缩包:请注意Linux下载solr-7.7.1.tgz,Windows下载solr-7.7.1.zip\
http://archive.apache.org/dist/lucene/solr/
步骤1-2:解压Solr-7.7.1压缩包
Windows下解压压缩包到对应的目录,我的路径是:
C:\myworking\solr-7.7.1
Linux下使用 tar 命令解压Solr压缩包:
tar zxvf solr-7.7.1.tgz -C /myworking
步骤1-3:进入bin目录运行Solr
Windows与Linux操作solr的命令都是一样的,但都需要进入到Solr的bin
目录下,我的目录是C:\myworking\solr-7.7.1\bin
。linux的目录使用cd
命令进入即可。
进入的到bin
目录下执行启动命令:
./solr start
启动完成后的控制台截图:
图2 控制台Solr启动完成图
随后我们访问http://localhost:8983
即能看到Solr Server端的Web
页面了
图3 Solr Server端 Web首页
步骤1-4:创建Core
Solr Core
的创建有两种方式,第一种是通过命令行的方式,第二种是在SolrWeb
首页中创建。
个人比较推荐第一种,原因有二,一是方便快捷在命令行一句话搞定,
Ctrl+c Ctrl+v
齐活儿,不用在页面上点来点去还得敲文字,二是所在公司大牛在实践过后说是如果采用的第二种方式创建出的Core
会有一些问题。本着听人话,吃饱饭的态度就采用第一种吧~ ~*大家可以实践一下然后分享给我哦。*当然两种方式还是要介绍下的。
使用命令行创建Core
我们只需要进入到上述的bin
目录,复制以下命令即可创建Core
,命令中的TestCore
为名称可以自行替换:
./solr create -c TestCore -d _default
使用Web
端创建Core
上述图3中左侧的列表第3个Core Admin
菜单项,点开后就明白怎么做了。
在Web
端查看TestCore
图4 选择TestCore
图5 TestCore详情图
介绍性的内容还是不罗列了,大家自己百度吧。Ik-Analyzer分词据说是国内最好用的中文分词,大部分人都用这个。目前Solr-7.7.1也自带了一个中文分词,具体的对比我没做过,等装完IK后大家回来可以进行下对比。同时欢迎分享给我哦。
IK分词GitHub:
https://github.com/magese/ik-analyzer-solr7
动态词库自动加载:
https://github.com/liang68/ik-analyzer-solr6
http://www.cnblogs.com/liang1101/articles/6395016.html
PS:关于动态词库自动加载,这个大家看一下下面这段引用描述后视项目情况选择要不要去研究下。
如果只是在我们原有的业务系统中简单集成Solr,那暂时没必要去了解动态词库自动加载。如果像商城等业务系统中,对于搜索模块是业务系统的核心之一,那么简单使用IK可能无法达到线上使用的要求。在IK分词器中默认是一次启动将主词库、停用词以及扩展词库全部加载完毕,后续如果再想要增加额外的扩展词,就必须得修改对应的扩展词表重新打包上传并重启服务方能生效,这种方式不适合应用与线上服务。那么到底如何实现这种无缝扩充词库呢?大家可以看看上面的博客。
步骤2-1:配置IK-analyzer jar包和词库
首先需要大家下载jar包和源码,我们下面需要放到Solr Server端对应的目录下。
IK分词jar包:
https://search.maven.org/remotecontent?filepath=com/github/magese/ik-analyzer/7.7.1/ik-analyzer-7.7.1.jar
IK分词GitHub源码:
https://github.com/magese/ik-analyzer-solr7
将下载好的ik-analyzer-7.7.1.jar
包放入Solr服务的webapp\WEB-INF\lib
目录下,我的目录全路径是:
C:\myworking\solr-7.7.1\server\solr-webapp\webapp\WEB-INF\lib
将下载好的ik-analyzer-solr7-master
源码下的src\main\resources
目录中的文件***(如下)***,放入到webapp\WEB-INF\classes
目录下:
① IKAnalyzer.cfg.xml 扩展配置文件
② ext.dic 扩展词库
③ stopword.dic 停止词库
④ ik.conf 动态词库配置文件
⑤ dynamicdic.txt 动态词库
我的目录全路径是:
C:\myworking\solr-7.7.1\server\solr-webapp\webapp\WEB-INF\classses
关于词库中同义词库、扩展词库、停止词库的介绍,可以看下面的blog:
https://blog.csdn.net/zcl_love_wx/article/details/52092894
步骤2-2. 配置TestCore
的server\solr\TestCore\conf\managed-schema
,添加IK分词器,示例如下:
<!-- ik分词器 -->
<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>
*PS:放在<schema name="default-config" version="1.6">
标签下。*同时在该标签下我们还需要配置field,请看步骤3。
Solr filed域的配置极为重要,filed的配置会影响到索引的创建和查询出的结果展示。
<!-- Solr Test search -->
<field name="title" type="text_ik" indexed="true" stored="true" required="true" multiValued="true" />
<field name="content" type="text_ik" indexed="true" stored="true" required="true" multiValued="true" />
<field name="filetype" type="string" indexed="true" stored="true" required="true" multiValued="false" />
<field name="uploadtime" type="string" indexed="false" stored="true" required="true" multiValued="false" />
<!-- 复制域,可以将多个Field复制到一个Field中,以便进行统一的检索,multiValued属性需要设置成true -->
<copyField source="content" dest="title" />
name:查询时的名称
type:这个是之前定义的FieldType的名称,在这使用的ik分词
indexed:是否索引(true/false)
stored:是否存储(是否将索引结果存储到索引库)
multivalued:是否多值(一般配合copyField使用)
动态filed
在定义
filed
时,可能会随着业务主线作出变更,那么每次在managed-schema
更改filed
后,还需重启Solr也是个麻烦事儿。那么在生产环境如此操作可能显得不是那么理想了。那么可以在变更时使用类似通配符的方式建立动态filed
,比如name="title"
可以写成name="fl_*"
,这样只要以fl_
开头的索引都可以被建立。
这里请注意Analyse Fieldname / FieldType:
右边的下拉列表,需要去选中ik分词text_ik
。我们可以看到输入中华人民共和国
关键字后所出现的分词效果。
图6 分词效果图
至此我们的Solr Server端基础版就搭建完成了,下面开始使用Spring boot结合SolrJ进行全文检索微服务的搭建。
Spring boot的基础知识不讲解了,下面我们采用Spring boot 2.1.3结合SolrJ 7.7.1完成全文检索微服务的实现。
下载源码
https://github.com/JasonGofen/SolrProject
准备两个doc文档,写入一些自定内容,放到指定目录下,当然也不一定非得要doc。以下是我准备的两个文件:
C:\solrfile\data\鹅鹅鹅.pdfC:\solrfile\data\静夜思.docx
创建项目,在pom.xml
引入SolrJ
的Maven依赖
<!-- SolrJ 7.7.1 API -->
<dependency>
<groupId>org.apache.solr</groupId>
<artifactId>solr-solrj</artifactId>
<version>7.7.1</version>
</dependency>
<!-- 解析文档内容工具包 -->
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-core</artifactId>
<version>1.9</version>
</dependency>
目录结构
├── src
│ └── main
│ ├── java
│ │ └── com.jasongofen
│ │ ├── client
│ │ │ └── SolrClient.java // Solr客户端
│ │ ├── config
│ │ │ ├── CorsConfig.java // 跨域配置文件
│ │ │ └── SolrConfigProperties.java // yml属性实例化配置文件
│ │ ├── test
│ │ │ └── SolrCURDTest.java // Solr API调用测试示例
│ │ ├── util
│ │ │ ├── ConvertUtil.java // 自定义转换工具类
│ │ │ └── TikaUtil.java // 提取文档内容工具类
│ │ └── SolrProjectApplication.java // Spring boot启动类
│ └── resources
│ ├── application.yml // 项目配置
│ ├── banner.txt // banner配置
│ └── logback-spring.xml // 日志配置
├── pom.xml // 依赖配置
└── README.md // 项目帮助文档
配置application.yml
中solr
节点下的属性值***(必须)***
# solr配置
solr:
# Solr Server端地址
server: localhost:8983 # 设置你的Solr Server访问地址
# Solr Core名称
core: TestCore # 设置你的Solr Core名称
# 上面准备的文档的所在本地路径
dir: C:\solrfile\data\ # 设置你的需要建立索引的文件所在目录
下面就可以运行项目了,SolrJ API调用请看以下内容。未完待续
基础的API调用代码在项目目录src\main\java\com.jasongofen.test\SolrCURDTest.java
文件中,该java
是一个Controller
可以以http
请求的方式模拟其他业务系统调用过程。
添加、修改索引
添加索引时首先使用HttpSolrClient
与Solr Server
建立连接,随后解析需要建立索引的文件*(至于需要结合现有的业务系统是采用http ftp
等方式从各自的文件Server中获取,还是另外的方式,请结合当前项目业务需要作扩展即可)*,接着把解析出的文件数据放到对应的索引位置,在设置索引内容时id
字段是必须要设置的且全局唯一,最后提交索引并关闭SolrClient
。
修改索引时,如果id
在索引库中已存在,则执行更新操作。
@GetMapping("/Add")
public void solrAdd throws Exception {
// 设置文件路径
List<String> files = new ArrayList<>;
files.add("鹅鹅鹅.pdf");
files.add("静夜思.docx");
// 获取Solr客户端
HttpSolrClient solr = SolrClient.getClient(solrConfigProperties.getServer);
String prefix = "";
for (String fi : files) {
System.out.println(fi);
// 取后缀名
prefix = ConvertUtil.getFileSufix(fi);
if (prefix.equalsIgnoreCase("txt") ||
prefix.equalsIgnoreCase("docx") ||
prefix.equalsIgnoreCase("doc") ||
prefix.equalsIgnoreCase("pdf")) {
String fileInfo = fi.split("\.");
String content = "";
// 获取文件流,取出文件内容
InputStream inputStream = new FileInputStream(solrConfigProperties.getDir + fi);
if (prefix.equals("txt")) {
content = TikaUtil.txt2String(inputStream);
} else if (prefix.equals("docx") || prefix.equals("doc") || prefix.equals("pdf")) {
content = TikaUtil.doc2String(inputStream);
} else {
inputStream.close;
}
// 添加索引
SolrInputDocument solrDoc = new SolrInputDocument;
String formatDate = ConvertUtil.formatDate;
// 执行添加 ps:如果id相同,则执行更新操作
solrDoc.addField("id", UUID.randomUUID.toString.toUpperCase.replace("-", ""));
solrDoc.addField("title", fileInfo[0]);
solrDoc.addField("content", content);
solrDoc.addField("filetype", prefix);
solrDoc.addField("uploadtime", formatDate);
solr.add(solrConfigProperties.getCore, solrDoc);
} else {
continue;
}
}
// 提交
solr.commit(solrConfigProperties.getCore);
solr.close;
}
查询
查询时因返回的是JSON串,并未做前端页面展示,请根据业务需求自行定制。
@GetMapping("/Query")
public SolrDocumentList solrQuery throws Exception {
HttpSolrClient solrClient = SolrClient.getClient(solrConfigProperties.getServer);
// 定义查询条件
Map<String, String> params = new HashMap<String, String>;
params.put("q", "*:*");
SolrParams mapSolrParams = new MapSolrParams(params);
//执行查询 第一个参数是collection,就是我们在solr中创建的core
QueryResponse response = solrClient.query(solrConfigProperties.getCore, mapSolrParams);
// 获取结果集
SolrDocumentList results = response.getResults;
for (SolrDocument result : results) {
// SolrDocument 数据结构为Map
System.out.println(result);
}
solrClient.close;
return results;
}
删除索引
需要删除索引时,根据id
去删除即可。
@GetMapping("/Delete")
public void solrDelete(@RequestParam("id") String id) throws Exception {
HttpSolrClient solrClient = SolrClient.getClient(solrConfigProperties.getServer);
// 通过id删除 执行要删除的collection(core)
solrClient.deleteById(solrConfigProperties.getCore, id);
// 还可以通过查询条件删除
// solrClient.deleteByQuery(solrConfigProperties.getCore, "查询条件");
// 提交删除
solrClient.commit(solrConfigProperties.getCore);
solrClient.close;
}
本文所用资源汇总:
本文已配置的 Solr7.7.1https://pan.baidu.com/s/11s18oJVKpEVc-AmZO1xkgA
本文源码https://github.com/JasonGofen/SolrProject
Solr 官网https://lucene.apache.org/solr/
Solr API 官方文档http://lucene.apache.org/solr/7_7_1/solr-solrj/index.html
Solr 中文文档(译版)https://www.w3cschool.cn/solr_doc/solr_doc-t3642fkr.html
JDK 8Java SE Development Kit 8 下载
Solr 7.7.1 压缩包http://archive.apache.org/dist/lucene/solr/
IK 分词 jar 包https://search.maven.org/remotecontent?filepath=com/github/magese/ik-analyzer/7.7.1/ik-analyzer-7.7.1.jar
IK 分词 GitHub 源码https://github.com/magese/ik-analyzer-solr7
动态词库自动加载
https://github.com/liang68/ik-analyzer-solr6
http://www.cnblogs.com/liang1101/articles/6395016.html
同义词典、扩展词典、停止词典介绍 Bloghttps://blog.csdn.net/zcl_love_wx/article/details/52092894
创建 Spring boot 项目的网址https://start.spring.io/
-END-
如果看到这里,说明你喜欢这篇文章,请转发。同时标星(置顶)本公众号可以第一时间接受到博文推送。1. 基友说:“自己整一个”HashMap为什么线程不安全?3.一致性Hash在负载均衡中的应用60个相见恨晚的神器工具
*请认真填写需求信息,我们会在24小时内与您取得联系。