PHP+Mysql+Sphinx高效的站内搜索引擎搭建详释 - 小众知识

PHP+Mysql+Sphinx高效的站内搜索引擎搭建详释

2013年01月27日 14:18:05 苏内容
  标签: PHP/Mysql/Sphinx/搜索引擎
阅读:7328

选择软件 致力于推进开源软件运动在大中华地区的发展, 投入了大量的资源来改进开源软件。
目前,选择软件 参与并改进的项目包括:

CRF++:

由日本人Taku Kudo 博士创立的采用条件随机场(CRF)方法对序列进行标注的软件包。我们对其进行了改进,显著的降低了CRF++的内存占用(降低幅度,取决于应用)。

Sphinx:

由俄罗斯人Andrew Aksyonoff 开发的高性能全文搜索软件包。我们为Sphinx 贡献了:

中文编码的数据源支持
采用Chih-Hao Tsai MMSEG算法的中文分词器
中文使用手册
本地化的技术支持服务
LibMMSeg:

LibMMSeg 是Coreseek.com为 Sphinx 全文搜索引擎设计的中文分词软件包,其在GPL协议下发行的中文分词法,采用Chih-Hao Tsai的MMSEG算法。

LibMMSeg 采用C++开发,同时支持Linux平台和Windows平台,切分速度大约在300K/s(PM-1.2G)。为什么要使用Sphinx



 

假设你现在运营着一个论坛,论坛数据已经超过100W,很多用户都反映论坛搜索的速度非常慢,那么这时你就可以考虑使用Sphinx了(当然其他的全文检索程序或方法也行)。

Sphinx是什么

Sphinx由俄罗斯人Andrew Aksyonoff 开发的高性能全文搜索软件包,在GPL与商业协议双许可协议下发行。

全文检索是指以文档的全部文本信息作为检索对象的一种信息检索技术。检索的对象有可能是文章的标题,也有可能是文章的作者,也有可能是文章摘要或内容。

Sphinx的特性

高速索引 (在新款CPU上,近10 MB/秒);高速搜索 (2-4G的文本量中平均查询速度不到0.1秒);高可用性 (单CPU上最大可支持100 GB的文本,100M文档); 提供良好的相关性排名;支持分布式搜索;  提供文档摘要生成;  提供从MySQL内部的插件式存储引擎上搜索 ;  支持布尔,短语, 和近义词查询;   支持每个文档多个全文检索域(默认最大32个); 支持每个文档多属性;   支持断词; 支持单字节编码与UTF-8编码;

下载并安装Sphinx

打开网址http://www.coreseek.cn/news/7/52/ 找到适合自己的操作系统的版本,比如我是Windows那么我就可以下载Coreseek Win32通用版本,Linux下可以下载源码包,自己编译安装。这里解释下为什么我们下载的程序叫Coreseek,Coreseek是基于Sphinx开发的一款软件,对Sphinx做了一些改动,在中文方面支持得比Sphinx好,所以我们使用之。

下载完成后,将程序解压到你想解压的地方,比如我就想解压到E盘根目录,之后修改目录名为Coreseek,大功告成Coreseek安装完成了,安装的目录是在E:\coreseek\。

使用Sphinx

我要使用Sphinx需要做以下几件事

1)、首先得有数据

2)、建立Sphinx配置文件

3)、生成索引

4)、启动Sphinx

5)、使用之(调用api或search.exe程序进行查询)

第1步:(导入数据)

我们建立测试所需要用到得数据库、表以及数据,篇幅有限,这些在附件中都有,下载后导入MySQL即可。

第2步:(建立配置文件)

接下来我们需要建立一个Sphinx的配置文件 E:\coreseek\etc\mysql.conf,将其内容改为下面这些:

source mysql

{type       = mysql //数据库类型sql_host   = localhost //数据库地址sql_user   = root  //数据库用户名sql_pass   =       //数据库密码sql_db     = test  //数据库名sql_port   = 3306  //端口号sql_query_pre   = SET NAMES utf8  //设置字符集sql_query       = SELECT id,addtime,title,content FROM postsql_attr_timestamp  = addtime}index mysql{source      = mysqlpath        = E:/coreseek/var/data/mysqlcharset_dictpath  = E:/coreseek/etc/charset_type      = zh_cn.utf-8}

searchd{listen         = 9312max_matches    = 1000pid_file       = E:/coreseek/var/log/searchd_mysql.pidlog            = E:/coreseek/var/log/searchd_mysql.logquery_log      = E:/coreseek/var/log/query_mysql.log}

先讲下这个配置文件中每项的含义。

source mysql{} 定义源名称为mysql,也可以叫其他的,比如:source xxx{}type  数据源类型 。

sql_* 数据相关的配置,比如sql_host,sql_pass什么的,这些不解释。

sql_query 建立索引时的查询命令,在这里尽可能不使用where或group by,将where与groupby的内容交给sphinx,由sphinx进行条件过滤与groupby效率会更高,注意:select 的字段必须包括一个唯一主键以及要全文检索的字段,where中要用到的字段也要select出来

sql_query_pre 在执行sql_query前执行的sql命令, 可以有多条。

sql_attr 以这个开头的配置项,表示属性字段,在where,orderby,groupby中出现的字段要分别定义一个属性,定义不同类型的字段要用不同的属性名,比如上面的sql_attr_timestamp就是时间戳类型。

index mysql{} 定义索引名称为mysql,也可以叫其他的,比如:index xxx{}

source 关联源,就是source xxx定义的。

path 索引文件存放路径,比如:E:/coreseek/var/data/mysql 实际存放在E:/coreseek/var/data/目录,然后创建多个名称为mysql后缀却不同的索引文件

charset_dictpath  指明分词法读取词典文件的位置,当启用分词法时,为必填项。在使用LibMMSeg作为分词 库时,需要确保词典文件uni.lib在指定的目录下

charset_type 字符集,比如charset_type = zh_cn.gbk

searchd{} sphinx守护进程配置

listen 监听端口

max_matches最大匹配数,也就是查找的数据再多也只返回这里设置的1000条

pid_file pid文件路径

log全文检索日志

query_log查询日志

好了,配置文件就这样,配置的参数还有很多,大家可以自己查文档。

第3步:(生成索引)

开始 -> 运行 -> 输入cmd回车,打开命令行工具

e:\coreseek\bin\indexer –config e:\coreseek\etc\mysql.conf –all

这一串东西其实就是调用indexer程序来生成所有索引

如果只想对某个数据源进行索引,则可以这样:

e:\coreseek\bin\indexer –config e:\coreseek\etc\mysql.conf 索引名称(索引名称指配置文件中所定义的)

–config,–all这些都是indexer程序的参数,想了解更多参数的朋友可以查看文档

运行命令后如果你没看到FATAL,ERROR这些东西,那么索引文件就算生成成功了,比如我看到得就是

………省略………using config file ‘e:\coreseek\etc\mysql.conf’…indexing index ‘mysql’…collected 4 docs, 0.0 MB………省略………

第4步:(启动Sphinx)

同样命令行下 :

e:\coreseek\bin\searchd –config e:\coreseek\etc\mysql.conf

运行后提示了一大堆东西

…省略…

using config file ‘e:\coreseek\etc\mysql.conf’…listening on all interfaces, port=9312accepting connections

不用管这些鸟文是啥意思,反正Sphinx是启动好了。

现在有一串鸟文的这个命令行是不能关的,因为关了Sphinx也就关了,如果觉得这样不爽,可以将Sphinx安装成系统服务,在后台运行,安装系统服务只需在命令行中输入以下命令:

e:\coreseek\bin\searchd –config e:\coreseek\etc\mysql.conf –install安装之后记得启动这个服务,不会启动那我没法,自己google。

第5步:(使用Sphinx)

在web根目录下建立一个search目录(当然不在根目录也行,同样目录名也可以随取),复制E:\coreseek\api\ sphinxapi.php文件到search目录(sphinxapi.php这个是sphinx官方提供的api),开始php程序的编写。

在search目录建立一个文件,名字叫啥都行,我管它叫index.php,其内容如下

setServer(‘localhost’, 9312); // 设置服务端,第一个参数sphinx服务器地址,第二个sphinx监听端口

$res = $sc->query(‘sphinx’, ‘mysql’); // 执行查询,第一个参数查询的关键字,第二个查询的索引名称,mysql索引名称(这个也是在配置文件中定义的),多个索引名称以,分开,也可以用*表示所有索引。

print_r($res);

打印结果:

Array (………省略………[matches] => Array([2] => Array([weight] => 2[attrs] => Array([addtime] => 1282622004))[4] => Array([weight] => 2[attrs] => Array([addtime] => 1282622079)))………省略………)

Matches中就是查询的结果了,但是仿佛不是我们想要的数据,比如titile,content字段的内容就没有查询出来,根据官方的说明是Sphinx并没有连接到MySQL去取数据,只是根据它自己的索引内容进行计算,因此如果想用Sphinx提供的API去取得我们想要的数据,还必须以查询的结果为依据,再次查询MySQL从而得到我们想要的数据。

查询结果中键值分别表示2唯一主键weight权重attrs sql_attr_*中配置至此,搜索引擎算是完成一大半了,剩下的大家可以自行完成。

比如:

while($row = mysql_fetch_assoc($query)) {…..}

Sphinx在windows下安装使用

前一阵子尝试使用了一下Sphinx,一个能够被各种语言(PHP/Python/Ruby/etc)方便调用的全文检索系统。网上的资料大多是在 linux环境下的安装使用,当然,作为生产环境很有必要部署在*nix环境下,作为学习测试,还是windows环境比较方便些。

本文旨在提供一种便捷的方式让Sphinx在windows下安装配置以支持中文全文检索,配置部分在linux下通用。

一、关于Sphinx

Sphinx 是一个在GPLv2 下发布的一个全文检索引擎,商业授权(例如, 嵌入到其他程序中)需要联系作者(Sphinxsearch.com)以获得商业授权。

一般而言,Sphinx是一个独立的搜索引擎,意图为其他应用提供高速、低空间占用、高结果相关度的全文搜索功能。Sphinx可以非常容易的与 SQL数据库和脚本语言集成。

当前系统内置MySQL和PostgreSQL 数据库数据源的支持,也支持从标准输入读取特定格式的XML数据。通过修改源代码,用户可以自行增加新的数据源(例如:其他类型的DBMS的原生支持)。

搜索API支持PHP、Python、Perl、Rudy和Java,并且也可以用作MySQL存储引擎。搜索API非常简单,可以在若干个小时之 内移植到新的语言上。

中文手册可以在这里获得(酷勤 网备用下载地址:sphinx_doc_zhcn_0.9.pdf)。

二、Sphinx在windows上的安装

1.直接在http://www.sphinxsearch.com/downloads.html找 到最新的windows版本,我这里下的是Win32 release binaries with MySQL support,下载后解压在D:\sphinx目录下;

2.在D:\sphinx\下新建一个data目录用来存放索引文件, 一个log目录方日志文件,复制D:\sphinx\sphinx.conf.in到D:\sphinx\bin\sphinx.conf(注意修改文件 名);

3.修改D:\sphinx\bin\sphinx.conf,我这里 列出需要修改的几个:

type            = mysql # 数据源,我这里是

mysql
sql_host        = localhost # 数据库服务器

sql_user        = root # 数据库用户名

sql_pass        = '' # 数据库密码

sql_db          = test # 数据库

sql_port        = 3306 # 数据库端口

sql_query_pre   = SET NAMES utf8 # 去掉此行前面的注释,如果你的数据库是uft8编码的

index test1
{

# 放索引的目录
 

path       = D:/sphinx/data/

# 编码
 

charset_type      = utf-8
 

#  指定utf-8的编码表
 

charset_table      = 0..9, A..Z->a..z, _, a..z, U+410..U+42F->U+430..U+44F, U+430..U+44F
 

# 简单分词,只支持0和1,如果要搜索中文,请指定为1
 

ngram_len        = 1

# 需要分词的字符,如果要搜索中文,去掉前面的注释
 

ngram_chars       = U+3000..U+2FA1F

}

# index test1stemmed : test1

# {
 

# path       = @CONFDIR@/data/test1stemmed
 # morphology      = stem_en

# }

 # 如果没有分布式索引,注释掉下面的内容

# index dist1

# {
 

# 'distributed' index type MUST be specified
 

# type        = distributed# local index to be searched
 

# there can be many local indexes configured

# local        = test1
 

# local        = test1stemmed

# remote agent
 

# multiple remote agents may be specified
 

# syntax is 'hostname:port:index1,[index2[,...]]
 

# agent        = localhost:3313:remote1
 

# agent        = localhost:3314:remote2,remote3

# remote agent connection timeout, milliseconds
 

# optional, default is 1000 ms, ie. 1 sec
 

# agent_connect_timeout = 1000

# remote agent query timeout, milliseconds
 

# optional, default is 3000 ms, ie. 3 sec
 

# agent_query_timeout      = 3000

# }

# 搜索服务需要修改的部分
searchd
{
 

# 日志
 log         = D:/sphinx/log/searchd.log

# PID file, searchd process ID file name
 pid_file       = D:/sphinx/log/searchd.pid# windows下启动searchd服务一定要注释掉这个
 

# seamless_rotate      = 1

}

4.导入测试数据

sql 文件在D:/sphinx/example.sql

C:\Program Files\MySQL\MySQL Server 5.0\bin>mysql -uroot test

5.建立索引

D:\sphinx\bin>indexer.exe test1 (备注:test1为 sphinx.conf 的 index test1() )Sphinx 0.9.8-release (r1533)Copyright (c) 2001-2008, Andrew Aksyonoff

using config file ‘./sphinx.conf’…indexing index ‘test1′…collected 4 docs, 0.0 MBsorted 0.0 Mhits, 100.0% donetotal 4 docs, 193 bytestotal 0.101 sec, 1916.30 bytes/sec, 39.72 docs/sec

D:\sphinx\bin>

6.搜索’test’试试

D:\sphinx\bin>search.exe test1Sphinx 0.9.8-release (r1533)Copyright (c) 2001-2008, Andrew Aksyonoff

using config file ‘./sphinx.conf’…index ‘test1′: query ‘test ‘: returned 3 matches of 3 total in 0.000 sec

displaying matches:1. document=1, weight=2, group_id=1, date_added=Wed Nov 26 14:58:59 2008id=1group_id=1group_id2=5date_added=2008-11-26 14:58:59title=test onecontent=this is my test document number one. also checking search withinphrases.2. document=2, weight=2, group_id=1, date_added=Wed Nov 26 14:58:59 2008id=2group_id=1group_id2=6date_added=2008-11-26 14:58:59title=test twocontent=this is my test document number two3. document=4, weight=1, group_id=2, date_added=Wed Nov 26 14:58:59 2008id=4group_id=2group_id2=8date_added=2008-11-26 14:58:59title=doc number fourcontent=this is to test groups

words:1. ‘test’: 3 documents, 5 hitsD:\sphinx\bin>

都所出来了吧。

6.测试中文搜索

修改test数据库中documents数据表,

UPDATE `test`.`documents` SET `title` = ‘测试中文’, `content` = ‘this is my test document number two,应该搜的到吧’ WHERE `documents`.`id` = 2;

重建索引:

D:\sphinx\bin>indexer.exe test1

搜索’中文’试试:

D:\sphinx\bin>search.exe 中文Sphinx 0.9.8-release (r1533)Copyright (c) 2001-2008, Andrew Aksyonoff

using config file ‘./sphinx.conf’…index ‘test1′: query ‘中文 ‘: returned 0 matches of 0 total in 0.000 sec

words:D:\sphinx\bin>

貌似没有搜到,这是因为windows命令行中的编码是gbk,当然搜不出来。我们可以用程序试试,在D:\sphinx\api下新建一个 foo.php的文件,注意utf-8编码

SetServer(’localhost’,9312);$result = $s->Query(’中文’);var_dump($result);?>

启动Sphinx searchd服务

D:\sphinx\bin>searchd.exeSphinx 0.9.8-release (r1533)Copyright (c) 2001-2008, Andrew Aksyonoff

WARNING: forcing –console mode on Windowsusing config file ‘./sphinx.conf’…creating server socket on 0.0.0.0:9312accepting connections

已经表示服务器已经开启 不要关闭 命令行 (目前本人无法将此服务安装成系统服务器 所以每次PHP测试前注意开启 searchd 服务)

执行PHP查询:

访问 http://www.wszwl.com/sphinx/api/foo.php (自己配置的虚拟主机)

结果是不是出来?剩下的工作就是去看手册,慢慢摸索高阶的配置。

Windows下的Sphinx+MySQL简单配置及调试

2010年01月15日 星期五 02:44 P.M.

首先我们要从 Sphinx 官网上 http://www.sphinxsearch.com/downloads.html 下载mysql-5.0.45-sphinxse-0.9.8-win32.zip 和 sphinx-0.9.8.1-win32.zip,假设你已经安装好了 MySQL

先将 mysql 服务停掉 解压 mysql-5.0.45-sphinxse-0.9.8-win32.zip 将 bin 和share 覆盖掉 mysql 目录中的 bin 和 share 解压 sphinx-0.9.8.1-win32.zip 到独立的目录,如:d:/www/sphinx/中接着开启 mysql 服务,建立 “test” 数据库,并导入 sql 语句,如下:

———————————————————–

CREATE TABLE `documents` (`id` int(11) NOT NULL auto_increment,`group_id` int(11) NOT NULL,`group_id2` int(11) NOT NULL,`date_added` datetime NOT NULL,`title` varchar(255) NOT NULL,`content` text NOT NULL,PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=5;

INSERT INTO `documents` VALUES (’1′, ’1′, ’5′, ’2008-09-13 21:37:47′, ‘test one’, ‘this is my test document number one. also checking search within phrases.’);INSERT INTO `documents` VALUES (’2′, ’1′, ’6′, ’2008-09-13 21:37:47′, ‘test two’, ‘this is my test document number two’);INSERT INTO `documents` VALUES (’3′, ’2′, ’7′, ’2008-09-13 21:37:47′, ‘another doc’, ‘this is another group’);INSERT INTO `documents` VALUES (’4′, ’2′, ’8′, ’2008-09-13 21:37:47′, ‘doc number four’, ‘this is to test groups’);

——————————————-实际上,这个新建立的表就是 Sphinx 中的 example.sql

我们的测试表已经建立完成,接下来我们要配置 sphinx-doc.conf 文件(重要)

先将 sphinx 下的 sphinx-min.conf 复制一份改名为 sphinx-doc.conf,接着 修改它:

# Minimal Sphinx configuration sample (clean, simple, functional)## type——————数据库类型,目前支持 mysql 与 pgsql# strip_html————是否去掉html 标签# sql_host————–数据库主机地址# sql_user————-数据库用户名# sql_pass————-数据库密码# sql_db————–数据库名称# sql_port————-数据库采用的端口# sql_query_pre——–执行sql前要设置的字符集,用utf8必须SET NAMES utf8# sql_query———–全文检索要显示的内容,在这里尽可能不使用where或 group by,将 where 与 groupby 的内容交给 sphinx,由 sphinx 进行条件过滤与 groupby 效率会更高# 注意: select 出来的字段必须至少包括一个唯一主键 (ARTICLESID) 以及要全文检索的字段,你计划原本在 where 中要用到的字段也要 select 出来# 这里不用使用orderby# sql_attr_ 开头的表示一些属性字段,你原计划要用在 where, orderby, groupby 中的字段要在这里定义(# 为自己添加的注释内容)

#source 数据源名:

source documents{type             = mysqlsql_host     = localhostsql_user      = rootsql_pass     = yourpasswordsql_db         = testsql_port       = 3306 # optional, default is 3306

sql_query_pre     = SET NAMES utf8sql_query     = \SELECT id, group_id, UNIX_TIMESTAMP(date_added) AS date_added, title, content \FROM documents

sql_attr_uint    = group_idsql_attr_timestamp   = date_added

sql_query_info    = SELECT * FROM documents WHERE id=$id}

index documents{source      = documents

#path   索引记录存放目录,如 d:/sphinx/data/cgfinal ,实际存放时会存放在d:/sphinx/data目录,然后创建多个 cgfinal名称,不同扩展名的索引文件。path          = d:/www/sphinx/data/docdocinfo      = externenable_star     = 1

min_word_len     = 3min_prefix_len     = 0min_infix_len     = 3charset_type    = sbcs

# 其他的配置如 min_word_len, charset_type, charset_table, ngrams_chars, ngram_len 这些则是支持中文检索需要设置的内容。# 如果检索的不是中文,则 charset_table, ngrams_chars, min_word_len 就要设置不同的内容,具体官方网站的论坛中有很多,大家可以去搜索看看。}

# mem_limit 索引使用内存最大限制,根据机器情况而定,默认是32M,太小的会影响索引的性能。indexer{mem_limit     = 32M}

# 搜索的守护进程配置# 在进行全文检索过程中,searchd要先开启,mysql在全文检索时才能连接到sphinx,由sphinx进行全文检索,再将结果返回给mysql# address 侦听请求的地址,不设置则侦听所有地址# port 侦听端口searchd{port     = 3312log       =d:/www/sphinx/logs/searched_doc.logquery_log     = d:/www/sphinx/logs/query_doc.logread_timeout    = 5max_children    = 30pid_file     = d:/www/sphinx/logs/searched-doc.pidmax_matches     = 1000seamless_rotate    = 0preopen_indexes    = 0unlink_old     = 1}

为了测试,我们的 Sphinx 配置文件已经写好,确保我们的 Mysql 数据库已经启动,如果没有启动则在 cmd 中键入” net start mysql “

接下来,我们的测试正式开始:

1,生成数据索引或重建索引:

(最好再复制一个 sphinx-doc.conf 配置文件,并把它放入 bin 文件夹中,下面的举例 假设我们已经这样做):

在 cmd 模式下:输入:

d:/www/sphinx/bin/indexer.exe –config d:/www/sphinx/bin/sphinx-doc.conf documents

2,运行检索守护进程 searchd.exe:

d:/www/sphinx/bin/searchd.exe –config d:/www/sphinx/bin/sphinx-doc.conf

如过这两步没有报错的话,说明我们的 Sphinx 已经正常运行了!可以通过 netstat -an查看是否 3312 端口是否处如监听状态。

3,现在来用 sphinx 自带的工具 search.exe 来测试一下:

测试:

索引关键字: this is m

D:\www\sphinx\bin>search.exe -c d:/www/sphinx/bin/sphinx-doc.conf this is m

结果:

Sphinx 0.9.8-release (r1371)Copyright (c) 2001-2008, Andrew Aksyonoff

using config file ‘d:/www/sphinx/bin/sphinx-doc.conf’…WARNING: index ‘documents’: invalid morphology option ‘extern’ – IGNOREDindex ‘documents’: query ‘this is m ‘: returned 4 matches of 4 total in 0.000 sc

displaying matches:1. document=1, weight=1, group_id=1, date_added=Sat Sep 13 21:37:47 2008id=1group_id=1group_id2=5date_added=2008-09-13 21:37:47title=test onecontent=this is my test document number one. also checking search withiphrases.2. document=2, weight=1, group_id=1, date_added=Sat Sep 13 21:37:47 2008id=2group_id=1group_id2=6date_added=2008-09-13 21:37:47title=test twocontent=this is my test document number two3. document=3, weight=1, group_id=2, date_added=Sat Sep 13 21:37:47 2008id=3group_id=2group_id2=7date_added=2008-09-13 21:37:47title=another doccontent=this is another group4. document=4, weight=1, group_id=2, date_added=Sat Sep 13 21:37:47 2008id=4group_id=2group_id2=8date_added=2008-09-13 21:37:47title=doc number fourcontent=this is to test groups

words:1. ‘this’: 4 documents, 4 hits

——————-

索引关键字: this is another group

D:\www\sphinx\bin>search.exe -c d:/www/sphinx/bin/sphinx-doc.conf this is another group

结果:

Sphinx 0.9.8-release (r1371)Copyright (c) 2001-2008, Andrew Aksyonoff

——–

到此sphinx在win上算正常运行了,sphinx-doc.conf文件配置比较灵活,根据你需要索引的数据库进行灵活配置来达到你需要的效果

如果配置过程中出现运行参数配置问题可以查看 doc/sphinx.html文件,里面对各种参数都要详细的说明

using config file ‘d:/www/sphinx/bin/sphinx-doc.conf’…WARNING: index ‘documents’: invalid morphology option ‘extern’ – IGNOREDindex ‘documents’: query ‘this is another group ‘: returned 1 matches of 1 totalin 0.000 sec

displaying matches:1. document=3, weight=4, group_id=2, date_added=Sat Sep 13 21:37:47 2008id=3group_id=2group_id2=7date_added=2008-09-13 21:37:47title=another doccontent=this is another group

words:1. ‘this’: 4 documents, 4 hits2. ‘another’: 1 documents, 2 hits3. ‘group’: 1 documents, 1 hits

扩展阅读