8月4日

page类,

分页使用到的,分页无非就是使用到类 select * from table limit FROM,TO

在数据库中做分页查询的时候,我们要想知道获取数据的起始位置和结束位置,就要知道每页显示的数据个数,

我们可以根据数据总个数和每页显示的数据个数算出来总页数。

page类

1
2
3
4
5
6
7
8
9
10
11
public class PageBean<T>(){
//1. 当前页数 从页面获取
private int currentPage;
//2. 每页显示数据个数,赋初值或者setter获取
private int currentCount;
//3. 总条数,从数据库获取
private int totalRecord;
//4. 总页数,计算得到
private int totalPage;
//5. 每页的显示数据,从数据库得到
List<T> list=new ArrayList<>();

getter()和setter()方法
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17



#### SearchRequest类

```java
public class SearchRequest {

private Integer From;
private Integer pageSize;
//.....其他查询条件
private String name;
private String age;

getter()和setter()方法
}

Controller层

1
2
3
4
5
6
7
8
9
10
11
@RequestMapping(value = "/Page.action")
public @ResponseBody PageBean<> SearchRecordPage(SearchRequest searchRequest, PageBean pagebean){
//
int totalRecord=service.getPageSize(searchRequest);
pageBean.setTotalRecord(totalRecord);pageBean.setTotalPage((int) Math.ceil((pageBean.getTotalRecord()*1.0)/pageBean.getCurrentCount()));
//获取当前点击页面的数据(pageBean前台传错来一个页面显示多少条,和页码数)
List<> list = service.getRecord(searchRequest,pageBean);
//返回前台数据
pageBean.setList(list);
return pageBean;
}

Service的书写

SearchRequest包含了From和pageSize

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public List<T> getRecord(SearchRequest searchRequest, PageBean<ResultClassName> pageBean) {
//数据库进行分页的方法searchrequest加入from 和to
//当前页面
int currentPage=pageBean.getCurrentPage();
//页面的显示个数
int currentCount=pageBean.getCurrentCount();
//根据页面算出数据库查询的起始位置
int from=currentCount*(currentPage-1);
//获取的数据个数
int pageSize=currentCount;
//将查询范围在查询条件里
searchRequest.setFrom(From);
searchRequest.setPageSize(pageSize);
//根据以上条件返回目的对象
pageBean.setList( Mapper.getRecord(searchRequest));
return pageBean;
}

SQL的写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<select id="getRepairRecord" resultType="ResultClassName"
parameterType="SearchRequest">
SELECT *
FROM 表名
<where>
<if test="name!=null and name!=''">
and name=#{name}</if>
<if test="age!=null and age!=''">
and age=#{age}
</if>
</where>
<if test="From!=null and pageSize!=null">
limit #{From},#{pageSize}
</if>
</select>

java8的lambda表达式:

前世-匿名类

举一个匿名类的例子:

Comparator接口:

1
2
3
public interface Comparator<T> {
int compare(T o1, T o2);
}

使用匿名类创建排序的比较方法:注意new Comparator

1
2
3
4
5
Collections.sort(words, new Comparator<String>(){
public int compare(String s1, String s2){
return Integer.compare(s1.length(),s2.length())
}
});

匿名类适用于需要函数对象的经典面向对象设计模式,特别是策略模式,上面的匿名类是排序字符串的具体策略。然而,匿名类确实过于冗长。

起到的作用是,新new了一个接口,接口一个方法为compare,有两个参数s1,s2,

为什么sort里面要有一个Comparator接口,这么麻烦

sort点进去有binarysort,不管Objcet实际是什么类型的,都可以使用接口中定义的方法。

可能会有个疑问,为什么不在Object这个超类中定义这个方法然后子类重写,而是要用实现接口呢。这个嘛,是因为大部分用不着这个功能,写上去就会用浪费,我们就用接口来弥补,你要你就实现接口。

Lambda表达式的今生

在 Java 8 中,语言形式化了这样的概念,即使用单个抽象方法的接口是特别的,应该得到特别的对待。即一个接口只有一个方法。

这些接口现在称为函数式接口,并且该语言允许你使用lambda 表达式或简称 lambda 来创建这些接口的实例。

Lambdas 在功能上与匿名类相似,但更为简洁。下面的代码使用 lambdas 替换上面的匿名类。清晰明了

1
2
Collections.sort(words,(s1,s2)->
Integer.compare(s1.length(),s2.length()))
1
2
3
4
5
new Comparator<String>(){
public int compare(String s1, String s2){
return Integer.compare(s1.length(),s2.length())
}
}

等价于

1
(s1,s2)->Integer.compare(s1.length(),s2.length())

右边的东西形成了一个函数,这个函数需要两个参数,s1,s2.

1
customSchemaRepository.findAll((root,criteriaQuery,criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder))

Lambda表达式的语法非常简洁,但是使用时有几个问题需要特别注意:

  1. 使用Lambda表达式必须具有接口,且要求接口中有且仅有一个抽象方法。
  2. 使用Lambda必须具有上下文推断。也就是方法的参数或局部变量类型必须为Lambda对应的接口类型,才能使用Lambda作为该接口的实例。

Lambda标准形式

(参数类型 参数名称) ‐> { 代码语句 }

说明:

  1. 小括号内:没有参数就留空(),多个参数就用逗号分隔。
  2. -> 是新引入的语法格式,代表指向动作。
  3. 大括号内的语法与传统方法体要求基本一致。

Lambda的省略:凡是可以根据上下文推导得知的信息,都可以省略

在Lambda表达式标准形式的基础上:

  1. 小括号内参数的类型可以省略;
  2. 如果小括号内只有一个参数,则小括号可以省略;
  3. 如果大括号内只有一个语句,则无论是否有返回值,都可以省略大括号、return关键字及语句分号。

综上所述,从 Java 8 开始,lambda 是迄今为止表示小函数对象的最佳方式。除非必须创建非函数式接口类型的实例,否则不要使用匿名类作为函数对象。

备注:有且仅有一个抽象方法的接口,称为“函数式接口”。

内连接(INNER JOIN)实例

LIKE 操作符用于在 WHERE 子句中搜索列中的指定模式。

1
SELECT column_name(s) FROM table_name WHERE column_name LIKE pattern

现在,我们希望从上面的 “Persons” 表中选取居住在以 “N” 开始的城市里的人:

我们可以使用下面的 SELECT 语句:

1
2
SELECT * FROM Persons
WHERE City LIKE 'N%'

TF-IDF(term frequency–inverse document frequency)

是一种用于信息检索与数据挖掘的常用加权技术。

TF是词频(Term Frequency),IDF是逆文本频率指数(Inverse Document Frequency)。

ES(elasticsearch)搜索引擎

什么是搜索?

根据一个搜索词,检索出所有包含该词的数据
例如:用户在搜索框输入一个词,客户端软件发送一个请求到后台,后台通过sql语句从数据库中找出相关条目(数据库会一条一条的对比),这就是一个最简单搜索原型

普通搜索面临的问题

1, 当数据量很大时,假如500G, 效率低。从用户角度,从点击搜索按钮到看到搜索结果可能要很长时间,1小时?2小时?用户疯掉

2, 当数据量达到1T,一台电脑已经放不下了,这时候就需要多台,这就是分布式。这时候数据就在不同的服务器了,一个客户端不可能去请求每台机器,所以就需要一个管理员角色,负责把客户端请求分发到每台机器,同时汇总结果返回给客户端

普通搜索速度简单优化(倒排索引)

数据库每个条目的名称进行分词,形成一个key为词,value为条目id的数据表。同时对用户输入的搜索词进行分词,检索出每个词在数据库中的id,求个交集,然后把这些id查不出返回就行了。

输入 复仇者联盟, 经过分词后变成
[复仇者,联盟]
倒排索引表也已经建好了,可能长这样
复仇者 4,5,6,11 数字为文档编号
联盟 5,9,11

倒排索引

需要根据属性的值来查找记录,这种索引表中的每一项都包括一个[属性值, 具有该属性值的各个记录的地址]。

由于不是由记录来确定属性值,而是由属性值来确定记录的位置,因而称为倒排索引(inverted index)。

带有倒排索引的文件我们称为倒排索引文件,简称倒排文件(inverted file)。

倒排列表用来记录有哪些文档包含了某个单词,一般在文档集合里会有很多文档 包含某个单词,每个文档会记录文档编号(DocID),单词在这个文档中出现的次数(TF)及单词在文档中哪些位置出现过等信息.这样与一个文档相关的信息被称做倒排索引项(Posting)。并不存储倒排索引项中的实际文档编号,而是代之以文档编号差值(D-Gap),原始的 3个文档编号分别是187、196和199,通过编号差值计算,在实际存储的时候就转化成了:187、9、3。

之所以要对文档编号进行差值计算,主要原因是为了更好地对数据进行压缩,原始文档编号一般都是大数值,通过差值计算,就有效地将大数值转换为了小数值,而这有助于增加数据的压缩率。

索引构建方法
简单法

索引的构建相当于从正排表到倒排表的建立过程。当我们分析完网页时 ,得到的是以网页为主码的索引表。

流程描述如下:

1)将文档分析成单词term标记,

2)使用hash去重单词term

3)对单词生成倒排列表

倒排列表就是文档编号DocID,没有包含其他的信息(如词频,单词位置等),这就是简单的索引。

这个简单索引功能可以用于小数据,例如索引几千个文档。然而它有两点限制:

1)需要有足够的内存来存储倒排表,对于搜索引擎来说, 都是G级别数据,特别是当规模不断扩大时 ,我们根本不可能提供这么多的内存。

2)算法是顺序执行,不便于并行处理。

合并法

归并法,即每次将内存中数据写入磁盘时,包括词典在内的所有中间结果信息都被写入磁盘,这样内存所有内容都可以被清空,后续建立索引可以使用全部的定额内存。

图4归并索引图4归并索引

如图4归并示意图:

合并流程:

1)页面分析,生成临时倒排数据索引A,B,当临时倒排数据索引A,B占满内存后,将内存索引A,B写入临时文件生成临时倒排文件,

\2) 对生成的多个临时倒排文件 ,执行多路归并 ,输出得到最终的倒排文件 ( inverted file)。

合并流程合并流程

索引创建过程中的页面分析 ,特别是中文分词为主要时间开销。算法的第二步相对很快。这样创建算法的优化集中在中文分词效率上。

假设只存在正向索引(forward index),那么就需要扫描索引库中的所有文档,找出所有包含关键词“华为手机”的文档,再根据打分模型进行打分,排出名次后呈现给用户。

得到正向索引的结构如下:

​ “文档1”的ID > 单词1:出现次数,出现位置列表;单词2:出现次数,出现位置列表;…………。

​ “文档2”的ID > 此文档出现的关键词列表。

[文档ID,关键词]

因为互联网上收录在搜索引擎中的文档的数目是个天文数字,这样的索引结构根本无法满足实时返回排名结果的要求。

就是每个关键词都要去扫描库中的所有文档

所以,搜索引擎会将正向索引重新构建为倒排索引,即把文件ID对应到关键词的映射转换为关键词到文件ID的映射

[关键词,文件ID]

img

  从词的关键字,去找文档。

单词-文档矩阵