2017-03-02 34 views
1

我有一个存储在MySQL数据库中的the Geonames database的副本,以及一个PHP应用程序,它允许用户在数据库中搜索他们的城市。如果他们用英文输入城市名称,那么它可以正常工作,但我希望他们能够用母语进行搜索。使用非拉丁字符搜索Geoname数据库

例如,他们应该可以搜索東京,而不是让日语人员搜索Tokyo,而应该能够搜索東京

地名数据库包含alternatenames柱, “alternatenames, comma separated, ascii names automatically transliterated, convenience attribute from alternatename table, varchar(10000)。”

例如,Tokyo行的alternatenames值为Edo,TYO,Tochiu,Tocio,Tokija,Tokijas,Tokio,Tokió,Tokjo,Tokyo,Toquio,Toquio - dong jing,Toquio - æ±äº¬,Tòquio,Tókýó,Tóquio,TÅkyÅ,dokyo,dong jing,dong jing dou,tokeiyw,tokkiyo,tokyo,twkyw,twqyw,Τόκιο,Токио,Токё,Токіо,ÕÕ¸Õ¯Õ«Õ¸,טוקיו,توكيو,توکیو,طوكيو,ܛܘܟÜܘ,ܜܘܟÜܘ,टोकà¥à¤¯à¥‹,டோகà¯à®•à®¿à®¯à¯‹,โตเà¸à¸µà¸¢à¸§,ტáƒáƒ™áƒ˜áƒ,东京,æ±äº¬,æ±äº¬éƒ½,ë„ì¿„

这些值完全不包含東京,但我猜测它们包含已经以某种方式编码或转换的形式。所以,我假设如果我对我的搜索字符串执行相同的编码/转换,那么我将能够匹配该行。例如:

mysql_query(sprintf(" 
    SELECT * FROM geoname 
    WHERE 
     MATCH(name, asciiname, alternatenames) 
     AGAINST (%s) 
    LIMIT 1", 
    iconv('UTF-8', 'ASCII', '東京') 
)); 

问题是我不知道该转换是什么。我尝试了很多iconv(),mb_convert_string()等组合,但没有运气。

MySQL表看起来是这样的:

CREATE TABLE `geoname` (
`geonameid` int(11) NOT NULL DEFAULT '0', 
`name` varchar(200) DEFAULT NULL, 
`asciiname` varchar(200) DEFAULT NULL, 
`alternatenames` mediumtext, 
`latitude` decimal(10,7) DEFAULT NULL, 
`longitude` decimal(10,7) DEFAULT NULL, 
`fclass` char(1) DEFAULT NULL, 
`fcode` varchar(10) DEFAULT NULL, 
`country` varchar(2) DEFAULT NULL, 
`cc2` varchar(60) DEFAULT NULL, 
`admin1` varchar(20) DEFAULT NULL, 
`admin2` varchar(80) DEFAULT NULL, 
`admin3` varchar(20) DEFAULT NULL, 
`admin4` varchar(20) DEFAULT NULL, 
`population` int(11) DEFAULT NULL, 
`elevation` int(11) DEFAULT NULL, 
`gtopo30` int(11) DEFAULT NULL, 
`timezone` varchar(40) DEFAULT NULL, 
`moddate` date DEFAULT NULL, 
PRIMARY KEY (`geonameid`), 
KEY `timezone` (`timezone`), 
FULLTEXT KEY `namesearch` (`name`,`asciiname`,`alternatenames`) 
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 

任何人都可以点我在正确的方向?

+0

'SHOW CREATE TABLE geoname'告诉你什么? – miken32

+1

并停止使用那些过时的,无保留的,不推荐使用的和不安全的[mysql_ *函数](http://stackoverflow.com/questions/12859942/why-shouldnt-i-use-mysql-functions-in-php)。 – miken32

+0

@ miken32:我不是,它只是一个简化的最小化示例。 –

回答

3

当我下载the Japan file并建立一个数据库这样的:

CREATE TABLE geonames (
    geonameid SERIAL, 
    name varchar(200), 
    asciiname varchar(200), 
    alternatenames varchar(10000), 
    latitude float, 
    longitude float, 
    featureclass varchar(1), 
    featurecode varchar(10), 
    countrycode varchar(2), 
    cc2 varchar(200), 
    admin1code varchar(20), 
    admin2code varchar(80), 
    admin3code varchar(20), 
    admin4code varchar(20), 
    population BIGINT, 
    elevation INT, 
    dem INT, 
    timezone varchar(40), 
    modificationdate DATE 
    ) CHARSET utf8mb4; 

然后我load the data这样的:

LOAD DATA INFILE '/tmp/JP.txt' INTO TABLE geonames CHARACTER SET utf8mb4; 

,并选择它是这样的:

SELECT alternatenames FROM geonames WHERE geonameid=1850147\G 

我得到这个:

*************************** 1. row *************************** 
alternatenames: Edo,TYO,Tochiu,Tocio,Tokija,Tokijas,Tokio,Tokió,Tokjo,Tokyo,Toquio,Toquio - dong jing,Toquio - 東京,Tòquio,Tókýó,Tóquio,Tōkyō,dokyo,dong jing,dong jing dou,tokeiyw,tokkiyo,tokyo,twkyw,twqyw,Τόκιο,Токио,Токё,Токіо,Տոկիո,טוקיו,توكيو,توکیو,طوكيو,ܛܘܟܝܘ,ܜܘܟܝܘ,टोक्यो,டோக்கியோ,โตเกียว,ტოკიო,东京,東京,東京都,도쿄 

我也可以做这样的搜索:

SELECT name FROM geonames WHERE alternatenames LIKE '%,東京,%'; 

这是说的很长的路要走:注意字符集声明时,我创建的表。我相信这是您创建数据库时未能做到的。

+1

+ 10。我们注意到可以用一个“正确”的字符集来创建表格,并且仍然以内容mojibake结束。使用'LOAD DATA INFILE'时,当'LOAD DATA INFILE'语句中未指定字符集时,MySQL服务器使用'character_set_database'系统变量的字符集。 – spencer7593

+1

'character_set_database'基于当前选择的数据库,所以它*应该*没问题,除非您执行'LOAD ... INTO otherdb.geonames'。无论如何,它并没有受到伤害,我已经编辑了这个问题,明确地将其包含在声明中。谢谢你的提示。 – miken32

+1

我想知道...... FULLTEXT搜索是否也会返回预期的行,在OP查询中使用MATCH? (我不打算在这里测试,我没有设置演示。)MySQL参考手册注意到与“表意语言,如中文和日文”有关的“内置全文分析器”的限制。 (我不怀疑,并且我并不是建议全文解析器是问题,我只是好奇这是否可能是一个额外的问题,似乎逗号字符在字之间就足够“停止”了。只是好奇,以确认是否是这种情况,但不足以测试自己) – spencer7593

2

推荐阅读:

https://www.joelonsoftware.com/articles/Unicode.html

http://kunststube.net/encoding/


在MySQL而言,什么是至关重要的是MySQL连接的字符集。这是MySQL服务器认为客户端在其通信中使用的字符集。

SHOW VARIABLES LIKE '%characterset%' 

如果没有设置正确,例如,客户端发送的latin1(ISO-8859-1),但MySQL服务器认为它正在接受UTF8,反之亦然,有一个为变为乱码潜力。

同样重要的是alternatenames列的字符集


处理多字节字符集的一个问题将是PHP sprintf函数。 PHP中的许多字符串处理函数都有“mutlibyte”等价物,可以正确处理包含多字节字符的字符串。

https://secure.php.net/manual/en/book.mbstring.php

不幸的是,没有内置mb_sprintf功能。

对于字符串的处理在PHP中,包括多字节字符/ charactersets更详细的说明:

https://secure.php.net/manual/en/language.types.string.php#language.types.string.details

摘录:

最终,这意味着写使用Unicode要看仔细,避免正确的程序那些不起作用的函数,而且很可能会破坏数据并使用行为正常的函数(通常来自intl和mbstring扩展)。但是,使用可以处理Unicode编码的函数仅仅是开始。无论该语言提供的功能如何,了解Unicode规范至关重要。

此外,谷歌搜索“utf8一路通过”可能会返回一些有用的注意事项。但请注意,这个咒语不是解决问题的灵丹妙药。


另一个可能的问题,MySQL参考手册中指出:

https://dev.mysql.com/doc/refman/5.7/en/fulltext-restrictions.html

13.9.5全文限制

表意语言,如中国和日本没有单词分隔符。因此,内置的全文分析器无法确定这些语言和其他语言中词语的开始和结束位置。

在MySQL 5.7.6中,提供了一个支持中文,日文和韩文的基于字符的ngram全文分析器(CJK)和一个支持日文的基于单词的MeCab分析器插件,可用于InnoDB和MySIAM表。