php使用百度自定义ocr
在互联网时代,人们希望信息像快餐食品一样包装:即食,无忧且按口大小(或字节大小)包装。 实际上,为了养活那些急躁而又饥饿的人,即使现在最谦虚的网站也可以提供各种快速格式的菜单:
- RSS是您的披萨家伙,将新鲜出炉的数据带到您家门口。
- 该博客是您当地的中国外卖店,提供您最喜欢的辣菜。
- 论坛是附近的聚餐(或者更恰当地说,是“动物屋”中的美食大战现场)。
- 搜索就像在您当地的自助餐厅吃到饱的夜晚一样:只要将食道和椅子保持住,就一次又一次地用心所需要的东西填满盘子。
幸运的是,PHP开发人员可以找到各种各样的RSS,博客和论坛软件来创建或修改站点。 尽管Google和其他公司实际上是无所不知的,并且会吸引访问量,但搜索引擎并不一定非常适合每个站点。
例如,如果您的网站上提供了成千上万个全新的和翻新的保时捷零件,则Google可能会在您的网站上进行广泛的搜索,例如“ Carrera零件”,但对于更具体的“ 1991年使用”,可能无法得出准确的结果保时捷911 Targa大灯挡板”查询。
如果您的内容高度专业化,或者访问者希望您的搜索功能与现实世界中的工作流程平行,那么最好使用适合您站点的本地搜索系统来扩展Web的全球搜索引擎。 (有关更多专门搜索的例子,请参见“ 十亿大海捞针 ”。)
探索如何向PHP网站添加快速,强大,开源和免费的搜索引擎。 这里很少开发可见的网站。 相反,重点在于提供有效搜索结果所需的组件:数据库,索引,搜索引擎和PHP应用程序接口(API)。
参观伟大的狮身人面像
要为您的站点提供自定义搜索功能,您必须具有数据源并具有搜索该源的能力。 对于Web应用程序,数据源通常是一个关系数据库,该数据库具有内置的某些形式的搜索。(Equal是一个简单的搜索运算符,SQL运算符LIKE
。)但是,某些搜索可能比数据库更专业。可能执行,或者搜索可能是如此复杂,以至于固有SQL JOIN
太慢了。
为了加快搜索速度,您可以重新排列表,从而简化基础查询。 (表和SQL查询优化在很大程度上取决于您的架构和引擎。在线搜索可找到大量有关数据库性能的文章和书籍。)或者,您可以添加专门的搜索引擎。 应用哪个搜索引擎还取决于数据的形式(和数量)以及预算。 提供许多选项:您可以将Google设备连接到网络,购买Endeca或其他大型商业搜索产品,或尝试使用Lucene。 但是在许多情况下,商业产品过于夸张或浪费了运营预算,而Lucene在2007年7月编写此代码时并未提供PHP API。
作为替代方案,可以考虑使用Sphinx ,它是一个开放源代码且免费的搜索引擎(如语音和啤酒),旨在极其快速地搜索文本。 例如,在具有将近300,000行的五个索引列的实时数据库中,其中每个列包含大约15个单词,Sphinx可以在1/100秒内(对于2个单词而言)产生“这些单词中的任何一个”搜索结果GHz AMD Opteron处理器,带有1 GB RAM,运行DebianLinux®Sarge)。
Sphinx具有许多功能,包括:
- 它可以索引您可以表示为字符串的任何数据。
- 它可以以不同的方式索引相同的数据。 有多个索引,每个索引都针对特定目的进行了调整,您可以选择最合适的索引来优化搜索结果。
- 它可以将属性与每个索引数据相关联。 然后,您可以使用一个或多个属性来进一步过滤搜索结果。
- 它支持形态,因此搜索单词“ cats”也将找到词根“ cat”。
- 您可以在许多机器之间分配Sphinx索引,以提供故障转移。
- 它可以创建任意长度的单词前缀索引和不同长度的中缀子字符串索引。 例如,零件号可能是10个字符宽。 前缀索引将与字符串开头锚定的所有可能的子字符串匹配。 中缀索引将匹配字符串中任何位置的子字符串。
- 您可以在MySQL V5中将其作为存储引擎运行,从而消除了对另一个守护进程的需求,这通常被视为附加故障点。
您可以在线找到所有功能的完整列表,也可以在Sphinx源代码随附的README文件中找到这些功能的完整列表。 Sphinx网站还列出了已部署Sphinx的几个项目。
Sphinx用C ++编写,使用GNU编译器构建,在支持的平台上支持64位,并在Linux,UNIX®,Microsoft®Windows®和Mac OS X上运行。构建Sphinx很简单:下载并提取代码,然后运行命令./configure && make && make install
。
默认情况下,Sphinx实用程序安装在/ usr / local / bin /中,所有Sphinx组件的配置文件为/usr/local/etc/sphinx.conf。
Sphinx具有三个组件:索引生成器,搜索引擎和命令行搜索实用程序:
- 索引生成器称为indexer 。 它查询您的数据库,在结果的每一行中为每一列建立索引,并将每个索引条目与该行的主键相关联。
- 搜索引擎是一个名为searchd的守护程序。 守护程序接收搜索项和其他参数,搜索一个或多个索引,然后返回结果。 如果匹配,则searchd返回一个主键数组。 给定这些键,应用程序可以对关联的数据库运行查询以查找包含匹配项的完整记录。 Searched通过端口3312上的套接字连接与应用程序通信。
- 便捷的搜索实用程序使您无需编写代码即可从命令行进行搜索。 如果searchd返回匹配项,则search查询数据库并显示匹配集中的行。 搜索实用程序对于调试Sphinx配置和执行即席搜索很有用。
此外,Sphinx,Andrew Aksyonoff和其他撰稿人的作者为PHP,Perl,C / C ++和其他编程语言提供了API。
搜索身体部位
假设Body-Parts.com销售用于稀有和可收藏汽车的车身零件-挡泥板,镀Chrome,保险杠等。 与现实世界一样,车身零件站点的访问者很可能会按制造商(例如,保时捷或制造等效产品的第三方),零件编号,品牌,型号,年份,状况(二手,新的,翻新的)搜索零件。 ),说明或这些属性的某种组合。
为了构建车身零件搜索功能,让我们使用MySQL V5.0作为数据存储和Sphinx搜索后台程序,以提供快速而准确的文本搜索。 MySQL V5.0是一个功能强大的数据库,但是其增强的全文本搜索功能并不是特别丰富。 实际上,它仅限于MyISAM表-一种不支持外键的表格式,因此可能用途有限。
清单1至4展示了与本示例相关的Body Parts模式的一部分。 您将分别看到Model( 清单1 ),Assembly( 清单2 ),Inventory( 清单3 )和Schematic( 清单4 )表。
型号表
清单1中显示的Model表很简单:label列枚举了一个模型的名称(“ Corvette”); 描述充当汽车的消费者友好肖像(“两门敞篷跑车;推出的第一年”); begin_production
和end_production
分别表示该版本的生产开始和结束的年份。 由于上述各列中的值不是唯一的,因此单独的ID代表每个四元组(标签,描述,begin_production,end_production),并且是其他表中的外键。
清单1.身体部位模型表
CREATE TABLE Model (
id int(10) unsigned NOT NULL auto_increment,
label varchar(7) NOT NULL,
description varchar(256) NOT NULL,
begin_production int(4) NOT NULL,
end_production int(4) NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB;
以下是Model表的一些示例数据:
INSERT INTO Model
(`id`, `label`, `description`, `begin_production`, `end_production`)
VALUES
(1,'X Sedan','Four-door performance sedan',1998,1999),
(3,'X Sedan','Four door performance sedan, 1st model year',1995,1997),
(4,'J Convertible','Two-door roadster, metal retracting roof',2002,2005),
(5,'J Convertible','Two-door roadster',2000,2001),
(7,'W Wagon','Four-door, all-wheel drive sport station wagon',2007,0);
组装表
组件是一个子系统,例如变速器或汽车上的所有玻璃。 业主查阅装配图和相关零件清单以查找替换零件。 清单2中所示的Assembly表也很简单:它将唯一ID与程序集标签和描述相关联。
清单2. Assembly表
CREATE TABLE Assembly (
id int(10) unsigned NOT NULL auto_increment,
label varchar(7) NOT NULL,
description varchar(128) NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB;
要继续,下面是Assembly表的一些示例数据:
INSERT INTO Assembly
(`id`, `label`, `description`)
VALUES
(1,'5-00','Seats'),
(2,'4-00','Electrical'),
(3,'3-00','Glasses'),
(4,'2-00','Frame'),
(5,'1-00','Engine'),
(7,'101-00','Accessories');
库存表
库存表是汽车零件的规范列表。 零件(例如,螺栓或灯泡)可能在每辆制造的汽车中和多个装配中,但该零件只出现在“库存”表中一次。 库存表中的每一行都包含:
- 唯一的32位整数serialno用于标识行。
- 字母数字部件号。 (该部件号是唯一的,并且可以用作主键。但是,由于它可以包含字母数字字符,因此不适合与Sphinx一起使用,因为Sphinx要求索引的每个记录都具有唯一的32位整数键。)
- 文字说明。
- 价格。
清单3中显示了库存表的规范。
清单3.库存表
CREATE TABLE Inventory (
id int(10) unsigned NOT NULL auto_increment,
partno varchar(32) NOT NULL,
description varchar(256) NOT NULL,
price float unsigned NOT NULL default '0',
PRIMARY KEY (id),
UNIQUE KEY partno USING BTREE (partno)
) ENGINE=InnoDB;
零件的(部分)列表可能如下所示:
INSERT INTO `Inventory`
(`id`, `partno`, `description`, `price`)
VALUES
(1,'WIN408','Portal window',423),
(2,'ACC711','Jack kit',110),
(3,'ACC43','Rear-view mirror',55),
(4,'ACC5409','Cigarette lighter',20),
(5,'WIN958','Windshield, front',500),
(6,'765432','Bolt',0.1),
(7,'ENG001','Entire engine',10000),
(8,'ENG088','Cylinder head',55),
(9,'ENG976','Large cylinder head',65);
示意图表
示意图表将零件与装配体和模型版本联系在一起。 因此,您将使用“示意图”表查找组成1979 J Class敞篷车发动机的所有零件。 示意图表中的每一行都有一个唯一的ID,一个外键指向库存表中的一行,一个外键标识装配,另一个键则指向模型表中的特定模型和版本。 这些行如清单4所示。
清单4.示意图表
CREATE TABLE Schematic (
id int(10) unsigned NOT NULL auto_increment,
partno_id int(10) unsigned NOT NULL,
assembly_id int(10) unsigned NOT NULL,
model_id int(10) unsigned NOT NULL,
PRIMARY KEY (id),
KEY partno_index USING BTREE (partno_id),
KEY assembly_index USING BTREE (assembly_id),
KEY model_index USING BTREE (model_id),
FOREIGN KEY (partno_id) REFERENCES Inventory(id),
FOREIGN KEY (assembly_id) REFERENCES Assembly(id),
FOREIGN KEY (model_id) REFERENCES Model(id)
) ENGINE=InnoDB;
为了加强表的用途,以下是原理图中的一小排行:
INSERT INTO `Schematic`
(`id`, `partno_id`, `assembly_id`, `model_id`)
VALUES
(1,6,5,1),
(2,8,5,1),
(3,1,3,1),
(4,5,3,1),
(5,8,5,7),
(6,6,5,7),
(7,4,7,3),
(8,9,5,3);
搜索表
通过定义这些表,可以轻松回答很多搜索:
- 显示特定型号的所有版本
- 列出组装特定模型和版本所需的所有组装
- 显示特定模型和版本的特定装配体中的所有零件
但是少数搜索特别昂贵:
- 查找任何型号和版本的零件均以“ WIN”开头的所有零件
- 查找描述中具有“漆”或“油漆”的部分
- 在说明中找到所有带有“黑色皮革”的零件
- 在说明中找到所有带有“油漆”的2002 J系列零件
这些搜索中的每一个都可能需要大量的JOIN
或昂贵的LIKE
子句,尤其是在Inventory和Schematic表很大的情况下。 此外,复杂的文本搜索完全超出了MySQL的功能。 要搜索大量文本数据,请考虑构建并使用Sphinx索引。
集成Sphinx软件
要将Sphinx应用于问题,必须定义一个或多个源以及一个或多个索引。
源标识要索引的数据库,提供身份验证信息,并定义用于构造每一行的查询。 可选地,源可以将一个或多个列标识为过滤器,或者将Sphinx称为组 。 您可以使用组来过滤结果。 例如,单词paint可能产生900个匹配项。 如果您只对特定模型车的匹配感兴趣,则可以使用模型组进行进一步过滤。
索引需要一个源(即一组行),并定义如何对从源中提取的数据进行分类。
您可以在sphinx.conf文件中定义源和索引。 Body Parts的来源是一个MySQL数据库。 清单5显示了名为catalog的源代码的部分定义-代码段指定了要连接到哪个数据库以及如何建立连接(主机,套接字,用户和密码)。
清单5.访问MySQL数据库的设置
source catalog
{
type = mysql
sql_host = localhost
sql_user = reaper
sql_pass = s3cr3t
sql_db = body_parts
sql_sock = /var/run/mysqld/mysqld.sock
sql_port = 3306
接下来,创建一个查询以生成要索引的行。 通常,您创建一个SELECT
语句,也许将许多表JOIN
在一起以产生一行。 但是,这里存在一个问题:搜索型号和年份必须使用Assembly表,但是零件号和零件说明只能在Inventory表中找到。 要运行,Sphinx必须能够将搜索结果绑定到32位整数主键。
为了获得正确格式的数据,请创建一个视图 -MySQL V5中的新构造,该构造将来自其他表的列组装为单个复合虚拟表。 使用视图,即使实时数据实际上位于其他表中,每种搜索所需的所有数据都位于一个位置。 清单6显示了用于定义名为Catalog的视图SQL。
清单6. Catalog视图将数据组装成虚拟表
CREATE OR REPLACE VIEW Catalog AS
SELECT
Inventory.id,
Inventory.partno,
Inventory.description,
Assembly.id AS assembly,
Model.id AS model
FROM
Assembly, Inventory, Model, Schematic
WHERE
Schematic.partno_id=Inventory.id
AND Schematic.model_id=Model.id
AND Schematic.assembly_id=Assembly.id;
如果使用前面显示的表和数据创建名为body_parts的数据库,则“目录”视图应类似于以下内容:
mysql> use body_parts;
Database changed
mysql> select * from Catalog;
+----+---------+---------------------+----------+-------+
| id | partno | description | assembly | model |
+----+---------+---------------------+----------+-------+
| 6 | 765432 | Bolt | 5 | 1 |
| 8 | ENG088 | Cylinder head | 5 | 1 |
| 1 | WIN408 | Portal window | 3 | 1 |
| 5 | WIN958 | Windshield, front | 3 | 1 |
| 4 | ACC5409 | Cigarette lighter | 7 | 3 |
| 9 | ENG976 | Large cylinder head | 5 | 3 |
| 8 | ENG088 | Cylinder head | 5 | 7 |
| 6 | 765432 | Bolt | 5 | 7 |
+----+---------+---------------------+----------+-------+
8 rows in set (0.00 sec)
在视图中,字段id
指向“库存”表中零件的条目。 partno
和description
列是要搜索的基本文本,而assembly
和model
列则作为组来进一步过滤结果。 有了适当的视图,构造源查询就很容易了。 清单7显示了名为catalog的源代码的其余定义。
清单7.创建要索引的行的查询
# indexer query
# document_id MUST be the very first field
# document_id MUST be positive (non-zero, non-negative)
# document_id MUST fit into 32 bits
# document_id MUST be unique
sql_query = \
SELECT \
id, partno, description, \
assembly, model \
FROM \
Catalog;
sql_group_column = assembly
sql_group_column = model
# document info query
# ONLY used by search utility to display document information
# MUST be able to fetch document info by its id, therefore
# MUST contain '$id' macro
#
sql_query_info = SELECT * FROM Inventory WHERE id=$id
}
sql_query
必须包含要用于后续查找的主键,并且必须包含要索引并用作组的所有字段。 这两个sql_group_column
条目声明可以使用Assembly和Model来过滤结果。 并且搜索实用程序使用sql_query_info
查找匹配的记录。 在查询中, $id
替换为searchd返回的每个主键。
最后的配置步骤是构建索引。 清单8显示了源目录的索引。
清单8.描述名为目录的源的一个可能索引
index catalog
{
source = catalog
path = /var/data/sphinx/catalog
morphology = stem_en
min_word_len = 3
min_prefix_len = 0
min_infix_len = 3
}
第1行指向sphinx.conf文件中的命名源。 第2行定义了索引数据的存储位置; 按照惯例,Sphinx索引存储在/ var / data / sphinx中。 第3行允许索引使用英语形态。 第5-7行告诉索引器仅索引三个字符或更多的单词,并为三个或更多字符的每个子字符串创建一个中缀索引。 (为便于参考,清单9展示了Body Parts的整个示例sphinx.conf文件。)
清单9.身体部位的示例sphinx.conf
source catalog
{
type = mysql
sql_host = localhost
sql_user = reaper
sql_pass = s3cr3t
sql_db = body_parts
sql_sock = /var/run/mysqld/mysqld.sock
sql_port = 3306
# indexer query
# document_id MUST be the very first field
# document_id MUST be positive (non-zero, non-negative)
# document_id MUST fit into 32 bits
# document_id MUST be unique
sql_query = \
SELECT \
id, partno, description, \
assembly, model \
FROM \
Catalog;
sql_group_column = assembly
sql_group_column = model
# document info query
# ONLY used by search utility to display document information
# MUST be able to fetch document info by its id, therefore
# MUST contain '$id' macro
#
sql_query_info = SELECT * FROM Inventory WHERE id=$id
}
index catalog
{
source = catalog
path = /var/data/sphinx/catalog
morphology = stem_en
min_word_len = 3
min_prefix_len = 0
min_infix_len = 3
}
searchd
{
port = 3312
log = /var/log/searchd/searchd.log
query_log = /var/log/searchd/query.log
pid_file = /var/log/searchd/searchd.pid
}
底部的searchd
部分配置searchd守护程序本身。 该部分中的条目应不言自明。 query.log尤其有用:它会在运行时显示每个搜索并显示结果,例如搜索的文档数和匹配总数。
建立并测试索引
现在,您可以为“身体部位”应用程序建立索引了。 为此:
- 通过键入以下内容来创建目录层次结构/ var / data / sphinx:
$ sudo mkdir -p /var/data/sphinx
- 假设MySQL正在运行,请使用以下代码运行indexer来创建索引。
清单10.创建索引
注意:$ sudo /usr/local/bin/indexer --config /usr/local/etc/sphinx.conf --all Sphinx 0.9.7 Copyright (c) 2001-2007, Andrew Aksyonoff using config file '/usr/local/etc/sphinx.conf'... indexing index 'catalog'... collected 8 docs, 0.0 MB sorted 0.0 Mhits, 82.8% done total 8 docs, 149 bytes total 0.010 sec, 14900.00 bytes/sec, 800.00 docs/sec
-all
参数重建sphinx.conf中列出的所有索引。 如果不需要重建每个索引,则可以使用其他参数重建较少的参数。 - 现在,您可以使用搜索工具使用下面显示的代码来测试索引。 (您不需要运行searchd就可以使用搜索。)
清单11.使用搜索测试索引
$ /usr/local/bin/search --config /usr/local/etc/sphinx.conf ENG Sphinx 0.9.7 Copyright (c) 2001-2007, Andrew Aksyonoff index 'catalog': query 'ENG ': returned 2 matches of 2 total in 0.000 sec displaying matches: 1. document=8, weight=1, assembly=5, model=7 id=8 partno=ENG088 description=Cylinder head price=55 2. document=9, weight=1, assembly=5, model=3 id=9 partno=ENG976 description=Large cylinder head price=65 words: 1. 'eng': 2 documents, 2 hits $ /usr/local/bin/search --config /usr/local/etc/sphinx.conf wind Sphinx 0.9.7 Copyright (c) 2001-2007, Andrew Aksyonoff index 'catalog': query 'wind ': returned 2 matches of 2 total in 0.000 sec displaying matches: 1. document=1, weight=1, assembly=3, model=1 id=1 partno=WIN408 description=Portal window price=423 2. document=5, weight=1, assembly=3, model=1 id=5 partno=WIN958 description=Windshield, front price=500 words: 1. 'wind': 2 documents, 2 hits $ /usr/local/bin/search \ --config /usr/local/etc/sphinx.conf --filter model 3 ENG Sphinx 0.9.7 Copyright (c) 2001-2007, Andrew Aksyonoff index 'catalog': query 'ENG ': returned 1 matches of 1 total in 0.000 sec displaying matches: 1. document=9, weight=1, assembly=5, model=3 id=9 partno=ENG976 description=Large cylinder head price=65 words: 1. 'eng': 2 documents, 2 hits
第一个命令/usr/local/bin/search --config /usr/local/etc/sphinx.conf ENG
,在零件号中发现了两次ENG
。 第二个命令/usr/local/bin/search --config /usr/local/etc/sphinx.conf wind
wind
在两个部分的描述中找到了子字符串wind
。 第三个命令将结果限制为model
为3
那些条目。
编写代码
最后,您现在可以编写PHP代码来调用Sphinx搜索引擎。 Sphinx PHP API很小,易于掌握。 清单12是一个小PHP应用程序,可以调用searchd来提取与上面显示的最后一个命令相同的结果(“查找名称中属于模型3的所有带有'cylinder'的零件”)。
清单12.从PHP调用Sphinx搜索引擎
<?php
include('sphinx-0.9.7/api/sphinxapi.php');
$cl = new SphinxClient();
$cl->SetServer( "localhost", 3312 );
$cl->SetMatchMode( SPH_MATCH_ANY );
$cl->SetFilter( 'model', array( 3 ) );
$result = $cl->Query( 'cylinder', 'catalog' );
if ( $result === false ) {
echo "Query failed: " . $cl->GetLastError() . ".\n";
}
else {
if ( $cl->GetLastWarning() ) {
echo "WARNING: " . $cl->GetLastWarning() . "
";
}
if ( ! empty($result["matches"]) ) {
foreach ( $result["matches"] as $doc => $docinfo ) {
echo "$doc\n";
}
print_r( $result );
}
}
exit;
?>
要测试代码,请为Sphinx创建日志目录,开始searchd,然后运行PHP应用程序,如下所示。
清单13. PHP应用程序
$ sudo mkdir -p /var/log/searchd
$ sudo /usr/local/bin/searchd --config /usr/local/etc/sphinx.conf
$ php search.php
9
Array
(
[fields] => Array
(
[0] => partno
[1] => description
)
[attrs] => Array
(
[assembly] => 1
[model] => 1
)
[matches] => Array
(
[9] => Array
(
[weight] => 1
[attrs] => Array
(
[assembly] => 5
[model] => 3
)
)
)
[total] => 1
[total_found] => 1
[time] => 0.000
[words] => Array
(
[cylind] => Array
(
[docs] => 2
[hits] => 2
)
)
)
输出为9 :匹配的唯一行的正确主键。 如果Sphinx进行匹配,则关联数组$result
包含一个名为results
的元素。 浏览一下print_r()
的输出以查看还返回了什么。
一提: total_found
是在索引中找到的匹配总数,而found
是返回的结果数。 两者可能有所不同,因为您可以更改每次返回多少个匹配项以及要返回哪一批匹配项,这对于分页较长的结果列表很有用。 请参阅API调用SetLimits()
。 分页的一个示例是使用以下命令来调用搜索引擎: $cl->SetLimits( ( $page - 1 ) * SPAN, SPAN )
返回第一,第二,第三(等)批次的SPAN
匹配项,具体取决于哪个页面将被显示。
探索狮身人面像的奥秘
Sphinx还有更多功能可以利用。 我在这里几乎还没有做过铺垫,但是您现在有了一个可以工作的真实示例,可以用来扩展您的专业知识。
仔细阅读该发行版附带的示例Sphinx配置文件/usr/local/etc/sphinx.conf.dist。 该文件中的注释解释了每个Sphinx参数可以执行的操作。 展示如何创建分布式冗余配置; 并说明如何继承基本设置以避免源和索引重复。 Sphinx README文件也是一个很好的信息来源,包括如何将Sphinx直接嵌入MySQL V5中-不需要守护进程。
下次,寻找比echo()
和print_r()
更好的解决方案来调试PHP代码。
翻译自: https://www.ibm.com/developerworks/opensource/library/os-php-sphinxsearch/index.html
php使用百度自定义ocr