前言
在使用mysql的时候,为了查询速度,我们都会使用索引这个东西
现在问题来了,索引对 like "%xx%" 是不生效的,这就意味着无法快速的模糊匹配查询数据,那么有什么办法解决这个问题吗?
倒排索引
例如有一组数据:
代码语言:javascript复制[
{
"name": "仙士可",
"keyword": "关键字123"
},
{
"name": "php程序员仙士可",
"keyword": "个人介绍xxx"
}
]
如果需要查询 name 里面包含仙士可的,一般做法是直接遍历所有数据,一个个查,那么有什么快速的方法吗?
我们或许可以这样实现:
将name里面的所有文字拆分,每个文字都对应数组的索引
代码语言:javascript复制仙=>0
士=>0
可=>0
p=>1
h=>1
p=>1
程=>1
序=>1
员=>1
仙=>1
士=>1
可=>1
去重一下:
代码语言:javascript复制仙=>0
士=>0
可=>0
p=>1
h=>1
程=>1
序=>1
员=>1
仙=>1
士=>1
可=>1
合并一下:
代码语言:javascript复制仙=>[0,1]
士=>[0,1]
可=>[0,1]
p=>[1]
h=>[1]
程=>[1]
序=>[1]
员=>[1]
当我们需要查询仙士可时,首先查询 仙 对应的数组索引,然后查询 士,可,最后根据属性存储的数组索引做交集,交集出的数组索引则是查询出来的数据.
记录所有属性值对应的数据内容位置,根据属性值去找对应数据内容,通过属性值去确定一个数据的内容,这个索引方式就称为倒排索引
分词
这个时候获取大家就发现了一个新的问题:当一个属性值存在几千个字符时,是不是代表着会存储几千个索引内容呢?这样岂不是非常耗费空间?
答案是:确实会,为了一定能够搜索到这个值,确实会存储几千个,但是实际上,文章内容并没有这么多个不同的字,中国常用字也就几千个,不管多少文章,其实常用汉字就几千个,并不会过于增加空间
这样的话,又可能会产生新的问题: 本身中文常用汉字只有几千个,那如果有几千万篇文章,岂不是意味着每一个字都会对应到几百万甚至上千万的文章id吗?这样岂不是跟没有索引一样?
这就涉及到了新的一个东西, 分词.
分词就是将连续的字序列按照一定的规范重新组合成词序列的过程。我们知道,在英文的行文中,单词之间是以空格作为自然分界符的,而中文只是字、句和段能通过明显的分界符来简单划界,唯独词没有一个形式上的分界符,虽然英文也同样存在短语的划分问题,不过在词这一层上,中文比之英文要复杂得多、困难得多。
分词分为几种类型:
词性编码 | 词性名称 | 注 解 |
---|---|---|
Ag | 形语素 | 形容词性语素。形容词代码为 a,语素代码g前面置以A。 |
a | 形容词 | 取英语形容词 adjective的第1个字母。 |
ad | 副形词 | 直接作状语的形容词。形容词代码 a和副词代码d并在一起。 |
an | 名形词 | 具有名词功能的形容词。形容词代码 a和名词代码n并在一起。 |
b | 区别词 | 取汉字“别”的声母。 |
c | 连词 | 取英语连词 conjunction的第1个字母。 |
dg | 副语素 | 副词性语素。副词代码为 d,语素代码g前面置以D。 |
d | 副词 | 取 adverb的第2个字母,因其第1个字母已用于形容词。 |
e | 叹词 | 取英语叹词 exclamation的第1个字母。 |
f | 方位词 | 取汉字“方” |
g | 语素 | 绝大多数语素都能作为合成词的“词根”,取汉字“根”的声母。 |
h | 前接成分 | 取英语 head的第1个字母。 |
i | 成语 | 取英语成语 idiom的第1个字母。 |
j | 简称略语 | 取汉字“简”的声母。 |
k | 后接成分 | |
l | 习用语 | 习用语尚未成为成语,有点“临时性”,取“临”的声母。 |
m | 数词 | 取英语 numeral的第3个字母,n,u已有他用。 |
Ng | 名语素 | 名词性语素。名词代码为 n,语素代码g前面置以N。 |
n | 名词 | 取英语名词 noun的第1个字母。 |
nr | 人名 | 名词代码 n和“人(ren)”的声母并在一起。 |
ns | 地名 | 名词代码 n和处所词代码s并在一起。 |
nt | 机构团体 | “团”的声母为 t,名词代码n和t并在一起。 |
nz | 其他专名 | “专”的声母的第 1个字母为z,名词代码n和z并在一起。 |
o | 拟声词 | 取英语拟声词 onomatopoeia的第1个字母。 |
p | 介词 | 取英语介词 prepositional的第1个字母。 |
q | 量词 | 取英语 quantity的第1个字母。 |
r | 代词 | 取英语代词 pronoun的第2个字母,因p已用于介词。 |
s | 处所词 | 取英语 space的第1个字母。 |
tg | 时语素 | 时间词性语素。时间词代码为 t,在语素的代码g前面置以T。 |
t | 时间词 | 取英语 time的第1个字母。 |
u | 助词 | 取英语助词 auxiliary |
vg | 动语素 | 动词性语素。动词代码为 v。在语素的代码g前面置以V。 |
v | 动词 | 取英语动词 verb的第一个字母。 |
vd | 副动词 | 直接作状语的动词。动词和副词的代码并在一起。 |
vn | 名动词 | 指具有名词功能的动词。动词和名词的代码并在一起。 |
w | 标点符号 | |
x | 非语素字 | 非语素字只是一个符号,字母 x通常用于代表未知数、符号。 |
y | 语气词 | 取汉字“语”的声母。 |
z | 状态词 | 取汉字“状”的声母的前一个字母。 |
un | 未知词 | 不可识别词及用户自定义词组。取英文Unkonwn首两个字母。(非北大标准,CSW分词中定义) |
识别文章中的所有字符,通过预设定/或者ai自动识别的方案,自动将一句话/一篇文章内的字符串拆分为一个个的词语:
代码语言:javascript复制php是世界上最好的语言.
拆分为:
代码语言:javascript复制php 是 世界上 最好的 语言
中文分词方案有很多,例如 scws,THULAC,结巴分词,等等 中文分词方案.
lucene
在上面,我们了解到了倒排索引,了解了中文分词,那么lucene就是现成的使用倒排索引实现的全文搜索引擎.
lucene还附带了中文分词等解决方案.
lucene 的大致存储结构为:
lucene field的类型:
为了使得lucene更好的标识存储,field的类型大致分为以下几种:
1:完全拆分字符实现索引
2:分词实现索引
3:只存储文档数据,不建立索引
4:只建立索引,数据不存储在文档
索引和查询流程为:
- 文档标明id存储
- 文档解析field
- 文档分析field,分词
- 建立索引,索引进入索引库
- 用户通过查询接口
- 创建查询语言
- lucene 执行查询,通过索引库获得数据
- 渲染数据
- 响应到用户端
elasticsearch
在原来的lucene 全文搜索引擎中,它仅仅是一个全文搜索架构,提供了完整的查询引擎架构,如果需要使用它,那就意味着要自己实现各种存储,查询的调用.
elasticsearch 进一步封装了lucene,封装 restful api操作存储对象.并且实现了分布式存储架构
中文文档:https://www.elastic.co/guide/cn/elasticsearch/guide/current/intro.html
安装与运行
docker 安装:
代码语言:javascript复制docker pull elasticsearch
sudo docker run -p 9200:9200 -p 9300:9300 --name elasticsearch
-e "discovery.type=single-node"
-e "cluster.name=elasticsearch"
-v ~/docker/volumn/elasticsearch/plugins:/usr/share/elasticsearch/plugins
-v ~/docker/volumn/elasticsearch/data:/usr/share/elasticsearch/data
-d elasticsearch
访问:http://127.0.0.1:9200/ 出现数据则表示运行成功
使用
elasticsearch 使用restful api 请求规范操作,意味着你可以使用postman,curl,等等http客户端进行操作.
例如使用curl:
新增一条数据:
代码语言:javascript复制tioncico@acbc32866c55 ~ % curl -X PUT --header 'Content-Type: application/json' http://127.0.0.1:9200/databasename/tablename/1 -d
'{"name":"仙士可","age":"24"}'
{"_index":"databasename","_type":"tablename","_id":"1","_version":1,"result":"created","_shards":{"total":2,"successful":1,"failed":0},"created":true}%
获取一条数据:
代码语言:javascript复制tioncico@acbc32866c55 ~ % curl -X GET --header 'Content-Type: application/json' http://127.0.0.1:9200/databasename/tablename/1
{"_index":"databasename","_type":"tablename","_id":"1","_version":1,"found":true,"_source": {"name":"仙士可","age":"24"}}% tioncico@acbc32866c55 ~ %
其他高级搜索操作可查看官方文档
本文为仙士可原创文章,转载无需和我联系,但请注明来自仙士可博客www.php20.cn
- 上一篇: 没有了
- 下一篇: wordpress国内网速慢解决网站加速及防DDOS攻击快速CF切换教程