用redis进行搜索优化的两种方法

为了确保安全与速度,除了增、删、改之外,我们通常不直接对数据库进行操作,而是利用 redis 或者 mencache 等缓存机制获取数据。如何使用 redis 进行搜索呢?本文通过姓名/拼音首字母搜索人物基本信息实例叙述两种 redis 搜索方式,适用的情况也有所不同。

环境

LNMP/Redis

方法一

将所有人物信息存入一个 string 格式的 key(user_all)中,搜索时遍历查找 key 的内容。

实例中将人物的 id(uid)、姓名(name)、拼音首字母(spell)等信息存入 user_all 键。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function search() {
$con = $_POST['con']; //接收搜索信息

//连接本地的 Redis 服务
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

$ret = json_decode($redis->get('user_all'), TRUE);//获取user_all所有数据
if (empty($ret)) {
return false;
}
$searchInfos = array();

//从第一位往后匹配
foreach ($ret as $k => $v) {
if (strpos($v['name'], $con) === 0 || strpos($v['spell'], strtoupper($con)) === 0) {
$searchInfos[] = $v;
}
}
if ($searchInfos) {
return $searchInfos;
} else {
return false;
}
}

注意:使用 get(key)的方式获取到的数据格式可能是 object(stdClass),遍历时需要用访问对象的方式获取数据,因此使用 json_decode($content, TRUE)函数将其变为 array 格式。

方法二

将每个人物的信息分别存入 string 格式的 key(以 prefixname_uid,prefix_spell_uid 的形式,如 user路飞_001,user_LF_001)中,通过 keys()对键名进行模糊查询,以获取人物信息。

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function search() {
$con = $_POST['con']; //接收搜索信息

//连接本地的 Redis 服务
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

$ret = $redis->keys('user_' . $con . '*');//获取所有匹配数据
if (empty($ret)) {
return false;
}
$searchInfos = array();

foreach ($ret as $k => $v) {
$searchInfos[] = $redis->get($v);
}
if ($searchInfos) {
return $searchInfos;
} else {
return false;
}
}

两种方法比较

两种方式均能获得搜索结果,也都有各自的优缺点:

第一种方式,进行增加、删除、修改操作时都需进行数据库查询,获取所有人物信息,添加到 user_all 键中,查询时直接进行字符串匹配;
第二种方式,需要对 redis 键进行全部查询操作,不适用于键特别多的情况。

其他

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//除掉字符串中的标点符号
function spellReplace($spell) {
$char = "。、!?:;﹑•"…‘’“”〝〞∕¦‖— 〈〉﹞﹝「」‹›〖〗】【»«』『〕〔》《﹐¸﹕︰﹔!¡?¿﹖﹌﹏﹋'´ˊˋ―﹫︳︴¯_ ̄﹢﹦﹤‐­˜﹟﹩﹠﹪﹡﹨﹍﹉﹎﹊ˇ︵︶︷︸︹︿﹀︺︽︾ˉ﹁﹂﹃﹄︻︼()# #";
$pattern = array(
"/[[:punct:]]/i", //英文标点符号
'/[' . $char . ']/u', //中文标点符号
'/[ ]{2,}/'
);
$str = preg_replace($pattern, '', $spell);
return $str;
}
//获取拼音首字母,如yuan zi jiang =>YZJ
function spellChar($spell) {
$new_name = '';
$nword = explode(" ", $spell);
foreach ($nword as $letter) {
$new_name .= $letter{0};
}
return strtoupper($new_name);
}