Optimize search SQL query (I hope :p)
authorChocobozzz <me@florianbigard.com>
Fri, 27 Jul 2018 13:20:10 +0000 (15:20 +0200)
committerChocobozzz <me@florianbigard.com>
Fri, 27 Jul 2018 13:23:05 +0000 (15:23 +0200)
server/models/utils.ts
server/models/video/video.ts

index 99e14658326adb5fb3fdb5d4dafcae8a625c9832..58a18c97a9788a2aab814f19925f7acbf8b9d820 100644 (file)
@@ -51,17 +51,6 @@ function createSimilarityAttribute (col: string, value: string) {
   )
 }
 
-function createSearchTrigramQuery (col: string, value: string) {
-  return {
-    [ Sequelize.Op.or ]: [
-      // FIXME: use word_similarity instead of just similarity?
-      Sequelize.where(searchTrigramNormalizeCol(col), ' % ', searchTrigramNormalizeValue(value)),
-
-      Sequelize.where(searchTrigramNormalizeCol(col), ' LIKE ', searchTrigramNormalizeValue(`%${value}%`))
-    ]
-  }
-}
-
 // ---------------------------------------------------------------------------
 
 export {
@@ -69,8 +58,7 @@ export {
   getSortOnModel,
   createSimilarityAttribute,
   throwIfNotValid,
-  buildTrigramSearchIndex,
-  createSearchTrigramQuery
+  buildTrigramSearchIndex
 }
 
 // ---------------------------------------------------------------------------
index 33d62926b094528cec394ec158b3c44f6fc40984..464dbf5975be036a393589d1e00fed720cdef926 100644 (file)
@@ -83,7 +83,7 @@ import { AccountVideoRateModel } from '../account/account-video-rate'
 import { ActorModel } from '../activitypub/actor'
 import { AvatarModel } from '../avatar/avatar'
 import { ServerModel } from '../server/server'
-import { buildTrigramSearchIndex, createSearchTrigramQuery, createSimilarityAttribute, getSort, throwIfNotValid } from '../utils'
+import { buildTrigramSearchIndex, createSimilarityAttribute, getSort, throwIfNotValid } from '../utils'
 import { TagModel } from './tag'
 import { VideoAbuseModel } from './video-abuse'
 import { VideoChannelModel } from './video-channel'
@@ -883,24 +883,24 @@ export class VideoModel extends Model<VideoModel> {
     }
 
     const attributesInclude = []
+    const escapedSearch = VideoModel.sequelize.escape(options.search)
+    const escapedLikeSearch = VideoModel.sequelize.escape('%' + options.search + '%')
     if (options.search) {
       whereAnd.push(
         {
-          [ Sequelize.Op.or ]: [
-            createSearchTrigramQuery('VideoModel.name', options.search),
-
-            {
-              id: {
-                [ Sequelize.Op.in ]: Sequelize.literal(
-                  '(' +
-                    'SELECT "video"."id" FROM "video" LEFT JOIN "videoTag" ON "videoTag"."videoId" = "video"."id" ' +
-                    'INNER JOIN "tag" ON "tag"."id" = "videoTag"."tagId" ' +
-                    'WHERE "tag"."name" = ' + VideoModel.sequelize.escape(options.search) +
-                  ')'
-                )
-              }
-            }
-          ]
+          id: {
+            [ Sequelize.Op.in ]: Sequelize.literal(
+              '(' +
+                'SELECT "video"."id" FROM "video" WHERE ' +
+                'lower(immutable_unaccent("video"."name")) % lower(immutable_unaccent(' + escapedSearch + ')) OR ' +
+                'lower(immutable_unaccent("video"."name")) LIKE lower(immutable_unaccent(' + escapedLikeSearch + '))' +
+                'UNION ALL ' +
+                'SELECT "video"."id" FROM "video" LEFT JOIN "videoTag" ON "videoTag"."videoId" = "video"."id" ' +
+                'INNER JOIN "tag" ON "tag"."id" = "videoTag"."tagId" ' +
+                'WHERE "tag"."name" = ' + escapedSearch +
+              ')'
+            )
+          }
         }
       )