【问题标题】:Postgresql full text search with TypeOrm使用 TypeOrm 的 Postgresql 全文搜索
【发布时间】:2021-09-01 02:32:56
【问题描述】:

有一些方法可以使用 Postgres 和 TypeOrm 处理全文搜索。我看过一些例子,但它们只适用于 Mysql。除了使用 Postgresql 外,我怎样才能获得与此等价的功能?

@Entity()
export class User {

    @PrimaryGeneratedColumn()
    id: string;

    @Index({ fulltext: true })
    @Column("varchar")
    name: string;
}

并使用查询构建器:

const searchTerm = "John";

const result = await connection.manager.getRepository(User)
            .createQueryBuilder()
            .select()
            .where(`MATCH(name) AGAINST ('${searchTerm}' IN BOOLEAN MODE)`)
            .getMany();

【问题讨论】:

  • "有一些方法可以使用 Postgres 和 TypeOrm 处理全文搜索" - 你怎么知道的?是的,MATCH(name) AGAINST ('${searchTerm}' IN BOOLEAN MODE) 绝对是 MySQL 特有的语法(也是一种 sql 注入)。
  • 这个问题对我来说毫无意义,因为我对 TypeOrm 很陌生,我需要一个更完整的例子,比如问题中的那个。谢谢!

标签: postgresql typeorm


【解决方案1】:

这是使用 tsvector 的替代方法,其中 query 是输入字符串。

      const songs = await getManager()
        .createQueryBuilder()
        .select('song')
        .from(Models.Song, 'song')
        .where(
          'to_tsvector(song.title) @@ to_tsquery(:query)',
          { query }
        )
        .getMany();

如果您希望包含停用词(You、A 等),并希望部分匹配。

      const songs = await getManager()
        .createQueryBuilder()
        .select('song')
        .from(Models.Song, 'song')
        .where(
          `to_tsvector('simple',song.title) @@ to_tsquery('simple', :query)`,
          { query: `${query}:*` }
        )
        .getMany();

如果您还想允许多字串(带空格)。

      const formattedQuery = query.trim().replace(/ /g, ' & ');
      const songs = await getManager()
        .createQueryBuilder()
        .select('song')
        .from(Models.Song, 'song')
        .where(
          `to_tsvector('simple',song.title) @@ to_tsquery('simple', :query)`,
          { query: `${formattedQuery}:*` }
        )
        .getMany();

【讨论】:

  • 这就是基于文本的搜索在 postgres 中应该如何进行。正则表达式的使用很好,但它们会极大地影响查询的性能。使用 tsvector() 和 tsquery() 也是 postgre 推荐的方法
  • 格式化查询有没有SQL注入风险?
  • 我不这么认为,但可能完全值得另一个堆栈溢出问题。
【解决方案2】:

对于不区分大小写的搜索,我通常使用ILIKE PostgreSQL 表达式。例如;

const searchTerm = "John";

const result = await connection.manager.getRepository(User)
  .createQueryBuilder()
  .select()
  .where('name ILIKE :searchTerm', {searchTerm: `%${searchTerm}%`})
  .getMany();

或者,如果您有名字和姓氏列。

const result = await connection.manager.getRepository(User)
  .createQueryBuilder()
  .select()
  .where('first_name ILIKE :searchTerm', {searchTerm: `%${searchTerm}%`})
  .orWhere('last_name ILIKE :searchTerm', {searchTerm: `%${searchTerm}%`})
  .getMany();

【讨论】:

    【解决方案3】:

    对于全文搜索 (FTS),我建议您在 WHERE 子句中使用 PostgreSQL 特定函数。 LIKE 和 ILIKE 运算符对于全文搜索来说太简单而且太慢了。我建议您也观看this 视频。它确实清楚而轻松地解释了如何使用 PostgreSQL 实现这样的功能,并在最后几分钟展示了它是如何使用 Node.js 实现的。

    希望对您有所帮助!如果还有什么可以帮助您的,请告诉我。

    【讨论】:

      猜你喜欢
      • 2018-07-22
      • 1970-01-01
      • 2020-12-18
      • 2012-11-01
      • 1970-01-01
      • 2013-03-09
      • 2011-04-14
      • 1970-01-01
      • 2016-06-18
      相关资源
      最近更新 更多