-> ) CHARSET=ascii ROW_FORMAT=Compact;
ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change som mysql>
如果你了解 ES 应该知道,ES 可以说是对 Lucene 的一个封装,里面关于倒排索引的实现就是通过 lucene 这个 jar 包提供的 API 实现的,所以下面讲的关于倒排索引的内容实际上都是 lucene 里面的内容。
三、倒排索引
首先我们还不能忘了我们之前提的搜索需求,先看下建立倒排索引之后,我们上述的查询需求会变成什么样子,
这样我们一输入“前”,借助倒排索引就可以直接定位到符合查询条件的古诗。
当然这只是一个很大白话的形式来描述倒排索引的简要工作原理。在 ES 中,这个倒排索引是具体是个什么样的,怎么存储的等等,这些才是倒排索引的精华内容。
1. 几个概念
在进入下文之前,先描述几个前置概念。
term
关键词这个东西是我自己的讲法,在 ES 中,关键词被称为 term。
postings list
还是用上面的例子,{静夜思, 望庐山瀑布}是 “前” 这个 term 所对应列表。在 ES 中,这些被描述为所有包含特定 term 文档的 id 的集合。由于整型数字 integer 可以被高效压缩的特质,integer 是最适合放在 postings list 作为文档的唯一标识的,ES 会对这些存入的文档进行处理,转化成一个唯一的整型 id。
于是乎就有了 term dictionary,ES 为了能快速查找到 term,将所有的 term 排了一个序,二分法查找。是不是感觉有点眼熟,这不就是 MySQL 的索引方式的,直接用 B+树建立索引词典指向被索引的数据。
term index
但是问题又来了,你觉得 Term Dictionary 应该放在哪里?肯定是放在内存里面吧?磁盘 io 那么慢。就像 MySQL 索引就是存在内存里面了。
但是如果把整个 term dictionary 放在内存里面会有什么后果呢?
内存爆了…
别忘了,ES 默认可是会对全部 text 字段进行索引,必然会消耗巨大的内存,为此 ES 针对索引进行了深度的优化。在保证执行效率的同时,尽量缩减内存空间的占用。
于是乎就有了 term index。
Term index 从数据结构上分类算是一个“Trie 树”,也就是我们常说的字典树。这是一种专门处理字符串匹配的数据结构,用来解决在一组字符串集合中快速查找某个字符串的问题。
这棵树不会包含所有的 term,它包含的是 term 的一些前缀(这也是字典树的使用场景,公共前缀)。通过 term index 可以快速地定位到 term dictionary 的某个 offset,然后从这个位置再往后顺序查找。就想右边这个图所表示的。(怎么样,像不像我们查英文字典,我们定位 S 开头的第一个单词,或者定位到 Sh 开头的第一个单词,然后再往后顺序查询)
lucene 在这里还做了两点优化,一是 term dictionary 在磁盘上面是分 block 保存的,一个 block 内部利用公共前缀压缩,比如都是 Ab 开头的单词就可以把 Ab 省去。二是 term index 在内存中是以 FST(finite state transducers)的数据结构保存的。
对于如何压缩,可能会有人觉得没有必要,”posting list 不是已经只存储文档 id 了吗?还需要压缩?”,但是如果在 posting list 有百万个 doc id 的情况,压缩就显得很有必要了。(比如按照朝代查询古诗?),至于为啥需要求交并集,ES 是专门用来搜索的,肯定会有很多联合查询的需求吧 (AND、OR)。
比如现在有 id 列表 [73, 300, 302, 332, 343, 372],转化成每一个 id 相对于前一个 id 的增量值(第一个 id 的前一个 id 默认是 0,增量就是它自己)列表是[73, 227, 2, 30, 11, 29]。在这个新的列表里面,所有的 id 都是小于 255 的,所以每个 id 只需要一个字节存储。
CREATE TABLE MYCAT_SEQUENCE (
name VARCHAR (50) NOT NULL comment “名称”,
current_value INT NOT NULL comment “当前值”,
increment INT NOT NULL DEFAULT 100 comment “步长”,
PRIMARY KEY (name)
) ENGINE = INNODB;
1
2
3
4
5
6
2)创建相关function
#取当前squence的值
DROP FUNCTION IF EXISTS mycat_seq_currval;
DELIMITER $$
CREATE FUNCTION mycat_seq_currval(seq_name VARCHAR(50))RETURNS VARCHAR(64) CHARSET ‘utf8′
BEGIN
DECLARE retval VARCHAR(64);
SET retval=’-999999999,NULL’;
SELECT CONCAT(CAST(current_value AS CHAR),’,’,CAST(increment AS CHAR)) INTO retval FROM
MYCAT_SEQUENCE WHERE NAME = seq_name;
RETURN retval;
END$$
DELIMITER ;
#设置 sequence 值
DROP FUNCTION IF EXISTS mycat_seq_setval;
DELIMITER $$
CREATE FUNCTION mycat_seq_setval(seq_name VARCHAR(50),VALUE INTEGER) RETURNS VARCHAR(64) CHARSET ‘utf8’
BEGIN
UPDATE MYCAT_SEQUENCE SET current_value = VALUE WHERE NAME = seq_name;
RETURN mycat_seq_currval(seq_name);
END$$
DELIMITER ;
#取下一个sequence的值
DROP FUNCTION IF EXISTS mycat_seq_nextval;
DELIMITER $$
CREATE FUNCTION mycat_seq_nextval(seq_name VARCHAR(50)) RETURNS VARCHAR(64) CHARSET ‘utf8′
BEGIN
UPDATE MYCAT_SEQUENCE SET current_value = current_value + increment
WHERE NAME = seq_name;
RETURN mycat_seq_currval(seq_name);
END$$
DELIMITER ;
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
26
27
28
29
30
31
32
33
3)sequence_db_conf.properties相关配置,指定sequence相关配置在哪个节点上:
例如:
注意:MYCAT_SEQUENCE表和以上的3个function,需要放在同一个节点上。function请直接在具体节点的数据库上执行,如果执行的时候报:
you might want to use the less safe log_bin_trust_function_creators variable
需要对数据库做如下设置:
windows下my.ini[mysqld]加上log_bin_trust_function_creators=1
linux下/etc/my.cnf下my.ini[mysqld]加上log_bin_trust_function_creators=1
修改完后,即可在mysql数据库中执行上面的函数.
使用示例:
SELECT next value for MYCATSEQ_SAM_TEST
insert into sam_test(id_,name_) values(next value for MYCATSEQ_SAM_TEST,’test’);
# 数据库表定义了自增,在mycat也定义了主键和自增,可以用如下方式
insert into sam_test(name_) values(‘test’);
1
2
3
4
测试
1.配置schema.xml
今天莫名其妙我的博客出现Error establishing a database connection,一看应该是数据连接不上了。首先看了下wp-config.php,发现无异常。重启nginx,更换php5均没有效果。网上查了下,说是http://blog.csdn.net/mwb310/article/details/53009920,众说纷纭,有文件格式错误,mysql版本错误等等,试了均无效。
想着不如先把sql dump一份备份,所以
mysqldump -uxxx -pxxx --dataname >wordpress.log
发现:
warning : 250 clients are using or haven’t closed the table properly
status : OK
wangchunwei.wp_statistics_search
warning : 156 clients are using or haven’t closed the table properly
status : OK
wangchunwei.wp_statistics_useronline
warning : 252 clients are using or haven’t closed the table properly
status : OK
wangchunwei.wp_statistics_visit
warning : 252 clients are using or haven’t closed the table properly
status : OK
wangchunwei.wp_statistics_visitor
warning : 252 clients are using or haven’t closed the table properly
status : OK
wangchunwei.wp_term_relationships
warning : 32 clients are using or haven’t closed the table properly
status : OK
wangchunwei.wp_term_taxonomy
warning : 31 clients are using or haven’t closed the table properly
status : OK
mysqldump: Got error: 145: Table ‘./xxx/wp_options’ is marked as crashed and should be repaired when using LOCK TABLES
网上参考了:
修复 MySQL 数据库数据表问题可以由 mysqlcheck 来解决,先用 mysqlcheck 查看一下:
# mysqlcheck -u root -p wordpress
Enter password:
然后添加 –auto-repair 参数自动修复,最好修复前备份一下数据库:
# mysqldump -u root -p wordpress > wordpress.sql
Enter password:
# mysqlcheck -u root -p wordpress --auto-repair
Enter password:
wordpress.wp_commentmeta
error : Table upgrade required. Please do "REPAIR TABLE `wp_commentmeta`" or dump/reload to fix it!
wordpress.wp_comments
error : Table upgrade required. Please do "REPAIR TABLE `wp_comments`" or dump/reload to fix it!
wordpress.wp_links
error : Table upgrade required. Please do "REPAIR TABLE `wp_links`" or dump/reload to fix it!
wordpress.wp_options
error : Table upgrade required. Please do "REPAIR TABLE `wp_options`" or dump/reload to fix it!
wordpress.wp_postmeta
error : Table upgrade required. Please do "REPAIR TABLE `wp_postmeta`" or dump/reload to fix it!
wordpress.wp_posts
error : Table upgrade required. Please do "REPAIR TABLE `wp_posts`" or dump/reload to fix it!
wordpress.wp_term_relationships OK
wordpress.wp_term_taxonomy
error : Table upgrade required. Please do "REPAIR TABLE `wp_term_taxonomy`" or dump/reload to fix it!
wordpress.wp_terms
error : Table upgrade required. Please do "REPAIR TABLE `wp_terms`" or dump/reload to fix it!
wordpress.wp_usermeta
error : Table upgrade required. Please do "REPAIR TABLE `wp_usermeta`" or dump/reload to fix it!
wordpress.wp_users
error : Table upgrade required. Please do "REPAIR TABLE `wp_users`" or dump/reload to fix it!
Repairing tables
wordpress.wp_commentmeta OK
wordpress.wp_comments OK
wordpress.wp_links OK
wordpress.wp_options OK
wordpress.wp_postmeta OK
wordpress.wp_posts OK
wordpress.wp_term_taxonomy OK
wordpress.wp_terms OK
wordpress.wp_usermeta OK
wordpress.wp_users OK
其次是更新表,这里的更新的时候是带主键值的(因为我是从另一个表获取数据再插入,要求主键不能变) 同样直接更新1000条数据, replace的操作要比insert on duplicate的操作低太多太多, 当insert瞬间完成(感觉)的时候,replace要7,8s, replace慢的原因我是知道的,在更新数据的时候,要先删除旧的,然后插入新的,在这个过程中,还要重新维护索引,所以速度慢,但为何insert on duplicate的更新却那么快呢。 在向老大请教后,终于知道,insert on duplicate 的更新操作虽然也会更新数据,但其对主键的索引却不会有改变,也就是说,insert on duplicate 更新对主键索引没有影响.因此对索引的维护成本就低了一些(如果更新的字段不包括主键,那就要另说了)。
mysql> explain select * from city_demo where city like 'Jinch%';
+----+-------------+-----------+-------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+-------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | city_demo | range | city | city | 20 | NULL | 2 | Using where |
+----+-------------+-----------+-------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)
mysql>
DELETE consum_record
FROM
consum_record,
(
SELECT
min(id) id,
user_id,
monetary,
consume_time
FROM
consum_record
GROUP BY
user_id,
monetary,
consume_time
HAVING
count(*) > 1
) t2
WHERE
consum_record.user_id = t2.user_id
and consum_record.monetary = t2.monetary
and consum_record.consume_time = t2.consume_time
AND consum_record.id > t2.id;
上面这条sql语句,仔细看一下,揣摩出思路也不难,大概也分为3步来理解:
(SELECT min(id) id, user_id, monetary, consume_time FROM consum_record GROUP BY user_id, monetary, consume_time HAVING count(*) > 1 ) t2 查询出重复记录形成一个集合(临时表t2),集合里是每种重复记录的最小ID
consum_record.user_id = t2.user_id and consum_record.monetary = t2.monetary and consum_record.consume_time = t2.consume_time关联判断重复基准的字段
SELECT CAST('[1,2,3]' as JSON) ;
SELECT CAST('{"opening":"Sicilian","variations":["pelikan","dragon","najdorf"]}' as JSON);
所有MYSQL JSON函数
Name
Description
JSON_APPEND()
Append data to JSON document
JSON_ARRAY()
Create JSON array
JSON_ARRAY_APPEND()
Append data to JSON document
JSON_ARRAY_INSERT()
Insert into JSON array-> Return value from JSON column after evaluating path; equivalent to JSON_EXTRACT().
JSON_CONTAINS()
Whether JSON document contains specific object at path
JSON_CONTAINS_PATH()
Whether JSON document contains any data at path
JSON_DEPTH()
Maximum depth of JSON document
JSON_EXTRACT()
Return data from JSON document->> Return value from JSON column after evaluating path and unquoting the result; equivalent to JSON_UNQUOTE(JSON_EXTRACT()).
JSON_INSERT()
Insert data into JSON document
JSON_KEYS()
Array of keys from JSON document
JSON_LENGTH()
Number of elements in JSON document
JSON_MERGE()
Merge JSON documents, preserving duplicate keys. Deprecated synonym for JSON_MERGE_PRESERVE()