Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/76.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 用于与列中每个单词的开头进行比较的索引_Sql_Postgresql_Psycopg2 - Fatal编程技术网

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';