-
-
Notifications
You must be signed in to change notification settings - Fork 751
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
pref: search index #1241
Closed
Closed
pref: search index #1241
Changes from 1 commit
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
628cb4a
feat: add tsvector for search
caoxing9 757d362
feat: add tsvector trigger
caoxing9 284252e
feat: search hits with full text search
caoxing9 eb6a77a
perf: optimize search query logic for speed
caoxing9 86aa21b
fix: search ts vector with blank
caoxing9 ea7acbe
fix: search e2e test
caoxing9 61f41d9
fix: index error when enable hidden match field for search
caoxing9 0d7f64f
perf: optimize search sql
caoxing9 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,11 +8,13 @@ export class VectorTransform { | |
constructor( | ||
public field: IFieldInstance, | ||
public knex: Knex.Client, | ||
public dbTableName: string | ||
public dbTableName: string, | ||
public columnPrefix?: string | ||
) { | ||
this.field = field; | ||
this.knex = knex; | ||
this.dbTableName = dbTableName; | ||
this.columnPrefix = columnPrefix; | ||
} | ||
|
||
getRawSql() { | ||
|
@@ -42,6 +44,11 @@ export class VectorTransform { | |
} | ||
} | ||
|
||
getPrefix() { | ||
const { columnPrefix } = this; | ||
return `${columnPrefix ? `${columnPrefix}.` : ''}`; | ||
} | ||
|
||
getMultipleRawSql() { | ||
const { field } = this; | ||
const { isStructuredCellValue, cellValueType } = field; | ||
|
@@ -70,8 +77,9 @@ export class VectorTransform { | |
field: { dbFieldName }, | ||
} = this; | ||
const tsColumnName = FullTextSearchQueryPostgresBuilder.getTsVectorColumnName(dbFieldName); | ||
const prefix = this.getPrefix(); | ||
return knex | ||
.raw(`?? = to_tsvector('simple', COALESCE(??, ''))`, [tsColumnName, dbFieldName]) | ||
.raw(`?? = to_tsvector('simple', COALESCE(${prefix}??, ''))`, [tsColumnName, dbFieldName]) | ||
.toQuery(); | ||
} | ||
|
||
|
@@ -82,11 +90,12 @@ export class VectorTransform { | |
} = this; | ||
const tsColumnName = FullTextSearchQueryPostgresBuilder.getTsVectorColumnName(dbFieldName); | ||
const precision = get(this.field, ['options', 'formatting', 'precision']) ?? 0; | ||
const prefix = this.getPrefix(); | ||
return knex | ||
.raw(`?? = to_tsvector('simple', COALESCE(ROUND(??::numeric, ${precision})::text, ''))`, [ | ||
tsColumnName, | ||
dbFieldName, | ||
]) | ||
.raw( | ||
`?? = to_tsvector('simple', COALESCE(ROUND(${prefix}??::numeric, ${precision})::text, ''))`, | ||
[tsColumnName, dbFieldName] | ||
) | ||
.toQuery(); | ||
} | ||
|
||
|
@@ -98,11 +107,12 @@ export class VectorTransform { | |
const timeZone = (options as IDateFieldOptions).formatting.timeZone; | ||
const tsColumnName = FullTextSearchQueryPostgresBuilder.getTsVectorColumnName(dbFieldName); | ||
// "TO_CHAR(TIMEZONE(?, ??), 'YYYY-MM-DD HH24:MI') | ||
const prefix = this.getPrefix(); | ||
|
||
return knex | ||
.raw( | ||
`?? = to_tsvector('simple', | ||
to_char((??)::timestamp AT TIME ZONE ?, 'YYYY-MM-DD HH24:MI:SS') | ||
to_char((${prefix}??)::timestamp AT TIME ZONE ?, 'YYYY-MM-DD HH24:MI:SS') | ||
)`, | ||
[tsColumnName, dbFieldName, timeZone] | ||
) | ||
|
@@ -114,9 +124,13 @@ export class VectorTransform { | |
knex, | ||
field: { dbFieldName }, | ||
} = this; | ||
const prefix = this.getPrefix(); | ||
const tsColumnName = FullTextSearchQueryPostgresBuilder.getTsVectorColumnName(dbFieldName); | ||
return knex | ||
.raw(`?? = to_tsvector('simple', COALESCE(??->>'title', ''))`, [tsColumnName, dbFieldName]) | ||
.raw(`?? = to_tsvector('simple', COALESCE(${prefix}??->>'title', ''))`, [ | ||
tsColumnName, | ||
dbFieldName, | ||
]) | ||
.toQuery(); | ||
} | ||
|
||
|
@@ -126,13 +140,14 @@ export class VectorTransform { | |
field: { dbFieldName }, | ||
} = this; | ||
const tsColumnName = FullTextSearchQueryPostgresBuilder.getTsVectorColumnName(dbFieldName); | ||
const prefix = this.getPrefix(); | ||
return knex | ||
.raw( | ||
`?? = to_tsvector('simple', | ||
COALESCE( | ||
( | ||
SELECT string_agg(elem::text, ' ') | ||
FROM jsonb_array_elements_text(??::jsonb) as elem | ||
FROM jsonb_array_elements_text(${prefix}??::jsonb) as elem | ||
), | ||
'' | ||
) | ||
|
@@ -149,13 +164,14 @@ export class VectorTransform { | |
} = this; | ||
const tsColumnName = FullTextSearchQueryPostgresBuilder.getTsVectorColumnName(dbFieldName); | ||
const precision = get(this.field, ['options', 'formatting', 'precision']) ?? 0; | ||
const prefix = this.getPrefix(); | ||
return knex | ||
.raw( | ||
`?? = to_tsvector('simple', | ||
COALESCE( | ||
( | ||
SELECT string_agg(ROUND(elem::numeric, ?)::text, ' ') | ||
FROM jsonb_array_elements_text(??::jsonb) as elem | ||
FROM jsonb_array_elements_text(${prefix}::jsonb) as elem | ||
), | ||
'' | ||
) | ||
|
@@ -172,6 +188,7 @@ export class VectorTransform { | |
} = this; | ||
const timeZone = (options as IDateFieldOptions).formatting.timeZone; | ||
const tsColumnName = FullTextSearchQueryPostgresBuilder.getTsVectorColumnName(dbFieldName); | ||
const prefix = this.getPrefix(); | ||
|
||
return knex | ||
.raw( | ||
|
@@ -182,7 +199,7 @@ export class VectorTransform { | |
to_char((elem::timestamp AT TIME ZONE ?), 'YYYY-MM-DD HH24:MI:SS'), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe we should use the formatter in the field to perform the conversion. |
||
' ' | ||
) | ||
FROM jsonb_array_elements_text(??::jsonb) as elem | ||
FROM jsonb_array_elements_text(${prefix}??::jsonb) as elem | ||
), | ||
'' | ||
) | ||
|
@@ -198,13 +215,14 @@ export class VectorTransform { | |
field: { dbFieldName }, | ||
} = this; | ||
const tsColumnName = FullTextSearchQueryPostgresBuilder.getTsVectorColumnName(dbFieldName); | ||
const prefix = this.getPrefix(); | ||
return knex | ||
.raw( | ||
`?? = to_tsvector('simple', | ||
COALESCE( | ||
( | ||
SELECT string_agg(elem->>'title', ' ') | ||
FROM jsonb_array_elements(??::jsonb) as elem | ||
FROM jsonb_array_elements(${prefix}??::jsonb) as elem | ||
), | ||
'' | ||
) | ||
|
@@ -305,22 +323,27 @@ export class FullTextSearchQueryPostgresBuilder { | |
return knex.raw(`UPDATE ?? Set ${sqls.join(',')}`, [dbTableName]).toQuery(); | ||
} | ||
|
||
getCreateTriggerFunctionSql(dbFieldName: string) { | ||
const { queryBuilder } = this; | ||
getColumnTriggerFunctionSql(field: IFieldInstance) { | ||
const { dbFieldName } = field; | ||
const { queryBuilder, dbTableName } = this; | ||
const knex = queryBuilder.client; | ||
const tsName = FullTextSearchQueryPostgresBuilder.getTsVectorColumnName(dbFieldName); | ||
// const tsName = FullTextSearchQueryPostgresBuilder.getTsVectorColumnName(dbFieldName); | ||
const transformer = new VectorTransform(field, knex, dbTableName, 'NEW'); | ||
const sql = transformer.getRawSql(); | ||
return knex | ||
.raw( | ||
` | ||
CREATE OR REPLACE FUNCTION update_${dbFieldName}_tsvector() | ||
RETURNS trigger AS | ||
$$ | ||
BEGIN | ||
NEW.?? = to_tsvector('simple', NEW.??); | ||
IF TG_OP = 'INSERT' OR NEW.?? IS DISTINCT FROM OLD.?? THEN | ||
NEW.${sql}; | ||
END IF; | ||
RETURN NEW; | ||
END; | ||
$$ LANGUAGE plpgsql;`, | ||
[tsName, dbFieldName] | ||
[dbFieldName, dbFieldName] | ||
) | ||
.toQuery(); | ||
} | ||
|
@@ -331,11 +354,11 @@ $$ LANGUAGE plpgsql;`, | |
return knex | ||
.raw( | ||
` | ||
CREATE TRIGGER update_${dbFieldName}_tsvector | ||
BEFORE INSERT OR UPDATE | ||
ON ?? | ||
FOR EACH ROW | ||
EXECUTE FUNCTION update_${dbFieldName}_tsvector();`, | ||
CREATE TRIGGER update_${dbFieldName}_tsvector | ||
BEFORE INSERT OR UPDATE | ||
ON ?? | ||
FOR EACH ROW | ||
EXECUTE FUNCTION update_${dbFieldName}_tsvector();`, | ||
[dbTableName] | ||
) | ||
.toQuery(); | ||
|
@@ -348,12 +371,13 @@ EXECUTE FUNCTION update_${dbFieldName}_tsvector();`, | |
excSqls.push(extensionSql); | ||
excSqls.push(this.getCreateTsVectorsSql(searchFields)); | ||
excSqls.push(this.getUpdateVectorsSql(searchFields)); | ||
// excSqls.push(this.getCreateTriggerSql(dbFieldName)); | ||
// excSqls.push(this.getCreateTriggerFunctionSql(dbFieldName)); | ||
searchFields.forEach((field) => { | ||
const { dbFieldName } = field; | ||
excSqls.push(this.getColumnTriggerFunctionSql(field)); | ||
excSqls.push(this.getCreateTriggerSql(dbFieldName)); | ||
excSqls.push(this.getCreateGinIndexSql(dbFieldName)); | ||
}); | ||
console.log('ppppppp', excSqls); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. remove |
||
return excSqls; | ||
} | ||
|
||
|
@@ -392,10 +416,10 @@ EXECUTE FUNCTION update_${dbFieldName}_tsvector();`, | |
const { searchFields } = this; | ||
const excSqls = [] as string[]; | ||
searchFields.forEach(({ dbFieldName }) => { | ||
excSqls.push(this.getDropTriggerSql(dbFieldName)); | ||
excSqls.push(this.getDropTriggerFnSql(dbFieldName)); | ||
excSqls.push(this.getDropTsIndexSql(dbFieldName)); | ||
excSqls.push(this.getDropGinIndexSql(dbFieldName)); | ||
// excSqls.push(this.getDropTriggerSql(dbFieldName)); | ||
// excSqls.push(this.getDropTriggerFnSql(dbFieldName)); | ||
}); | ||
|
||
return excSqls; | ||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
all ::jsonb is not nessesary