Sql 用于与列中每个单词的开头进行比较的索引
所以我有一张桌子Sql 用于与列中每个单词的开头进行比较的索引,sql,postgresql,psycopg2,Sql,Postgresql,Psycopg2,所以我有一张桌子 id | name | gender ---+-----------------+------- 0 | Markus Meskanen | M 1 | Jack Jackson | M 2 | Jane Jackson | F 我已经创建了一个索引 CREATE INDEX people_name_idx ON people (LOWER(name)); 然后,我问 SELECT * FROM people WHERE name L
id | name | gender
---+-----------------+-------
0 | Markus Meskanen | M
1 | Jack Jackson | M
2 | Jane Jackson | F
我已经创建了一个索引
CREATE INDEX people_name_idx ON people (LOWER(name));
然后,我问
SELECT * FROM people WHERE name LIKE LOWER('Jack%');
其中,%(name)s
是用户的输入。但是,它现在只匹配整个专栏的开头,但我希望它匹配任何单词的开头。我不喜欢使用“%Jack%”
,因为它也会导致单词中间的无效结果
有没有一种方法可以创建索引,使每个单词都有一个单独的行
编辑:如果名字很长,比如“迈克尔·杰克逊的长子鲍勃”它应该与任何单词的开头匹配,也就是说,Mich
将与Michael
匹配,Fir
将与First
匹配,但是ackson
不会与任何东西匹配,因为它不是从一开始就匹配的
编辑2:我们有300万行,因此性能是一个问题,因此我主要关注索引。如果您知道单词是空格分隔的,您可以这样做
SELECT * FROM people WHERE name LIKE LOWER('Jack%') or name LIKE LOWER(' Jack%') ;
要获得更多控制,您可以将RegEx与MySQl一起使用
参见Postgres有两种索引类型来帮助全文搜索:GIN和GIST索引(我认为GIN是更常用的一种) 中的索引有一个简要概述。每个索引类都有更广泛的文档,以及关于这个主题的大量博客(一个又一个) 这些选项可以加快您尝试执行的搜索速度。您可以使用它们查找名称内的文本:
create table ci(id int, name text);
insert into ci values
(1, 'John McEnroe Blackbird Petrus'),
(2, 'Michael Jackson and Blade');
select id, name
from ci
where name ~ 'Pe+'
;
返回:
1 John McEnroe Blackbird Petrus
或者可以使用类似的,其中substring(name,)不为null
在这里检查:的功能正是您想要的
您需要创建以下任一项:
CREATE INDEX people_name_idx ON people USING GIST (name gist_trgm_ops);
或:
之后,这些查询可以使用上面的一个索引:
SELECT * FROM people WHERE name ILIKE '%Jack%';
SELECT * FROM people WHERE name ~* '\mJack';
As还能够通过前缀匹配进行搜索。但FTS的设计并不能有效地做到这一点,它最适合匹配词素。不过,如果你想取得最好的成绩,我建议你也尝试一下&衡量每一项。在FTS中,您的查询如下所示:
SELECT * FROM people WHERE to_tsvector('english', name) @@ to_tsquery('english', 'Jack:*');
注意:但是,如果您的查询筛选器(Jack
)来自用户输入,则上述两个查询都需要一些保护(也就是说,在i类
中,你需要转义%
和
字符,在regexp类中,你需要转义更多,在FTS类中,你需要用一些解析器解析查询并生成一个有效的FTS'tsquery
查询,因为要如果其参数无效,则
将给您一个错误。在plainto_tsquery()
中,您不能使用前缀匹配查询)
注2:带有名称~*'\mJack'
的regexp变体最适合英文名称。如果您想使用整个unicode范围(即,您想使用字符,如æ
),则需要稍微不同的模式。例如:
SELECT * FROM people WHERE name ~* '(^|\s|,)Jack';
这将适用于大多数名称,此外,这将与一些旧名称的真正前缀匹配,如O'Brian
最短的更改将是较低(“%Jack%”)
在文本中攻击Jack,但是在这里使用正则表达式似乎是合理的。如果某人有中间名,会发生什么?我认为你不需要将其转换为小写。@VaoTsun这不会找到Jack Jackson
,因为他的名字前面没有空格,或者会找到Jane Jackson
,因为她后面没有空格 surname@TimBiegeleisen它应该像第一个和最后一个名称一样匹配。该操作使用的是Postgres,而不是MySQL。这不使用索引。我有3000000多行数据,使用如LOWER(“%Jack%”)
将非常慢。嗯,这看起来不错,我必须进一步研究它
SELECT * FROM people WHERE name ~* '(^|\s|,)Jack';