Drop reset-enriched flag and add description filter
The --reset-enriched flag was effectively a no-op: the enrichment worker claims rows solely on enrichment_requested_at, and SetEnriched rewrites enriched_at regardless, so clearing it never changed whether a row was re-processed. Remove the flag and the resetEnriched parameter on RequestEnrichmentByIDs, which now only stamps enrichment_requested_at. Add a --without-description filter to the list and reenrich commands, backed by a new described predicate on CommonTrackerPatternFilter, so an operator can target catalog rows that still lack a description. Signed-off-by: Émile Ré <emile@probo.com>
This commit is contained in:
@@ -836,29 +836,27 @@ ORDER BY pattern ASC
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RequestEnrichmentByIDs arms enrichment on the given common tracker
|
// RequestEnrichmentByIDs arms enrichment on the given common tracker
|
||||||
// patterns. When resetEnriched is true it also clears enriched_at so rows
|
// patterns by stamping enrichment_requested_at, which is the only column
|
||||||
// that previously reached a terminal state are re-processed. Returns the
|
// the enrichment worker claims on. Already-enriched rows are re-processed
|
||||||
// number of rows re-queued. This is the async fallback path; the
|
// too: the worker overwrites enriched_at and the description when it runs.
|
||||||
// synchronous enricher service is preferred.
|
// Returns the number of rows re-queued. This is the async fallback path;
|
||||||
|
// the synchronous enricher service is preferred.
|
||||||
func (ps *CommonTrackerPatterns) RequestEnrichmentByIDs(
|
func (ps *CommonTrackerPatterns) RequestEnrichmentByIDs(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
tx pg.Tx,
|
tx pg.Tx,
|
||||||
ids []gid.GID,
|
ids []gid.GID,
|
||||||
resetEnriched bool,
|
|
||||||
) (int64, error) {
|
) (int64, error) {
|
||||||
q := `
|
q := `
|
||||||
UPDATE common_tracker_patterns
|
UPDATE common_tracker_patterns
|
||||||
SET
|
SET
|
||||||
enrichment_requested_at = NOW(),
|
enrichment_requested_at = NOW(),
|
||||||
enriched_at = CASE WHEN @reset_enriched THEN NULL ELSE enriched_at END,
|
|
||||||
updated_at = NOW()
|
updated_at = NOW()
|
||||||
WHERE
|
WHERE
|
||||||
id = ANY(@ids)
|
id = ANY(@ids)
|
||||||
`
|
`
|
||||||
|
|
||||||
args := pgx.StrictNamedArgs{
|
args := pgx.StrictNamedArgs{
|
||||||
"ids": ids,
|
"ids": ids,
|
||||||
"reset_enriched": resetEnriched,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := tx.Exec(ctx, q, args)
|
result, err := tx.Exec(ctx, q, args)
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ type CommonTrackerPatternFilter struct {
|
|||||||
commonThirdPartyID *gid.GID
|
commonThirdPartyID *gid.GID
|
||||||
keyword *string
|
keyword *string
|
||||||
linked *bool
|
linked *bool
|
||||||
|
described *bool
|
||||||
state *CommonTrackerPatternEnrichmentState
|
state *CommonTrackerPatternEnrichmentState
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,6 +117,14 @@ func (f *CommonTrackerPatternFilter) WithLinked(linked *bool) *CommonTrackerPatt
|
|||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithDescribed filters on whether the pattern has a non-empty
|
||||||
|
// description: true keeps only described rows, false keeps only rows with
|
||||||
|
// a blank description.
|
||||||
|
func (f *CommonTrackerPatternFilter) WithDescribed(described *bool) *CommonTrackerPatternFilter {
|
||||||
|
f.described = described
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
func (f *CommonTrackerPatternFilter) WithState(state *CommonTrackerPatternEnrichmentState) *CommonTrackerPatternFilter {
|
func (f *CommonTrackerPatternFilter) WithState(state *CommonTrackerPatternEnrichmentState) *CommonTrackerPatternFilter {
|
||||||
f.state = state
|
f.state = state
|
||||||
return f
|
return f
|
||||||
@@ -165,6 +174,12 @@ func (f *CommonTrackerPatternFilter) SQLFragment() string {
|
|||||||
ELSE common_third_party_id IS NULL
|
ELSE common_third_party_id IS NULL
|
||||||
END
|
END
|
||||||
AND
|
AND
|
||||||
|
CASE
|
||||||
|
WHEN @filter_described::boolean IS NULL THEN TRUE
|
||||||
|
WHEN @filter_described::boolean THEN description != ''
|
||||||
|
ELSE description = ''
|
||||||
|
END
|
||||||
|
AND
|
||||||
CASE
|
CASE
|
||||||
WHEN @filter_state_queued::boolean THEN enrichment_requested_at IS NOT NULL
|
WHEN @filter_state_queued::boolean THEN enrichment_requested_at IS NOT NULL
|
||||||
WHEN @filter_state_enriched::boolean THEN
|
WHEN @filter_state_enriched::boolean THEN
|
||||||
@@ -184,6 +199,7 @@ func (f *CommonTrackerPatternFilter) SQLArguments() pgx.StrictNamedArgs {
|
|||||||
"filter_common_third_party_id": nil,
|
"filter_common_third_party_id": nil,
|
||||||
"filter_keyword": nil,
|
"filter_keyword": nil,
|
||||||
"filter_linked": nil,
|
"filter_linked": nil,
|
||||||
|
"filter_described": nil,
|
||||||
"filter_state_queued": false,
|
"filter_state_queued": false,
|
||||||
"filter_state_enriched": false,
|
"filter_state_enriched": false,
|
||||||
"filter_state_unenriched": false,
|
"filter_state_unenriched": false,
|
||||||
@@ -217,6 +233,10 @@ func (f *CommonTrackerPatternFilter) SQLArguments() pgx.StrictNamedArgs {
|
|||||||
args["filter_linked"] = *f.linked
|
args["filter_linked"] = *f.linked
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if f.described != nil {
|
||||||
|
args["filter_described"] = *f.described
|
||||||
|
}
|
||||||
|
|
||||||
if f.state != nil {
|
if f.state != nil {
|
||||||
switch *f.state {
|
switch *f.state {
|
||||||
case CommonTrackerPatternEnrichmentStateQueued:
|
case CommonTrackerPatternEnrichmentStateQueued:
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ func newCmdList(f *cmdutil.Factory) *cobra.Command {
|
|||||||
flagKeyword string
|
flagKeyword string
|
||||||
flagState string
|
flagState string
|
||||||
flagWithCommonThirdParty bool
|
flagWithCommonThirdParty bool
|
||||||
|
flagWithoutDescription bool
|
||||||
flagSort string
|
flagSort string
|
||||||
flagOrder string
|
flagOrder string
|
||||||
flagLimit int
|
flagLimit int
|
||||||
@@ -58,6 +59,7 @@ func newCmdList(f *cmdutil.Factory) *cobra.Command {
|
|||||||
cmd.Flags().StringVar(&flagKeyword, "keyword", "", "Filter by pattern/description substring")
|
cmd.Flags().StringVar(&flagKeyword, "keyword", "", "Filter by pattern/description substring")
|
||||||
cmd.Flags().StringVar(&flagState, "state", "", "Filter by enrichment state (queued, enriched, unenriched)")
|
cmd.Flags().StringVar(&flagState, "state", "", "Filter by enrichment state (queued, enriched, unenriched)")
|
||||||
cmd.Flags().BoolVar(&flagWithCommonThirdParty, "with-common-third-party", false, "Filter by whether the pattern is linked to a common third party (true/false); ignored when not set")
|
cmd.Flags().BoolVar(&flagWithCommonThirdParty, "with-common-third-party", false, "Filter by whether the pattern is linked to a common third party (true/false); ignored when not set")
|
||||||
|
cmd.Flags().BoolVar(&flagWithoutDescription, "without-description", false, "Only patterns with a blank description")
|
||||||
cmd.Flags().StringVar(&flagSort, "sort", "confidence", "Sort field: pattern, confidence, created, updated, enriched")
|
cmd.Flags().StringVar(&flagSort, "sort", "confidence", "Sort field: pattern, confidence, created, updated, enriched")
|
||||||
cmd.Flags().StringVar(&flagOrder, "order", "", "Sort order: asc, desc (default depends on field)")
|
cmd.Flags().StringVar(&flagOrder, "order", "", "Sort order: asc, desc (default depends on field)")
|
||||||
cmd.Flags().IntVarP(&flagLimit, "limit", "L", 50, "Maximum rows to return (0 for all)")
|
cmd.Flags().IntVarP(&flagLimit, "limit", "L", 50, "Maximum rows to return (0 for all)")
|
||||||
@@ -81,7 +83,12 @@ func newCmdList(f *cmdutil.Factory) *cobra.Command {
|
|||||||
withCommonThirdParty = &flagWithCommonThirdParty
|
withCommonThirdParty = &flagWithCommonThirdParty
|
||||||
}
|
}
|
||||||
|
|
||||||
filter, err := buildListFilter(flagTrackerType, flagMatchType, flagKeyword, flagState, withCommonThirdParty)
|
var described *bool
|
||||||
|
if flagWithoutDescription {
|
||||||
|
described = new(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
filter, err := buildListFilter(flagTrackerType, flagMatchType, flagKeyword, flagState, withCommonThirdParty, described)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -287,7 +294,7 @@ func parseOrderBy(sort, order string) (page.OrderBy[coredata.CommonTrackerPatter
|
|||||||
|
|
||||||
func buildListFilter(
|
func buildListFilter(
|
||||||
trackerType, matchType, keyword, state string,
|
trackerType, matchType, keyword, state string,
|
||||||
withCommonThirdParty *bool,
|
withCommonThirdParty, described *bool,
|
||||||
) (*coredata.CommonTrackerPatternFilter, error) {
|
) (*coredata.CommonTrackerPatternFilter, error) {
|
||||||
filter := coredata.NewCommonTrackerPatternFilter()
|
filter := coredata.NewCommonTrackerPatternFilter()
|
||||||
|
|
||||||
@@ -326,6 +333,10 @@ func buildListFilter(
|
|||||||
filter.WithLinked(withCommonThirdParty)
|
filter.WithLinked(withCommonThirdParty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if described != nil {
|
||||||
|
filter.WithDescribed(described)
|
||||||
|
}
|
||||||
|
|
||||||
return filter, nil
|
return filter, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,18 +30,18 @@ import (
|
|||||||
|
|
||||||
func newCmdReenrich(f *cmdutil.Factory) *cobra.Command {
|
func newCmdReenrich(f *cmdutil.Factory) *cobra.Command {
|
||||||
var (
|
var (
|
||||||
flagIDs []string
|
flagIDs []string
|
||||||
flagLinkedBanner string
|
flagLinkedBanner string
|
||||||
flagLinkedOrg string
|
flagLinkedOrg string
|
||||||
flagCommonThirdParty string
|
flagCommonThirdParty string
|
||||||
flagTrackerType string
|
flagTrackerType string
|
||||||
flagKeyword string
|
flagKeyword string
|
||||||
flagState string
|
flagState string
|
||||||
flagConcurrency int
|
flagWithoutDescription bool
|
||||||
flagResetEnriched bool
|
flagConcurrency int
|
||||||
flagDryRun bool
|
flagDryRun bool
|
||||||
flagYes bool
|
flagYes bool
|
||||||
flagEnqueue bool
|
flagEnqueue bool
|
||||||
)
|
)
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
@@ -62,8 +62,8 @@ func newCmdReenrich(f *cmdutil.Factory) *cobra.Command {
|
|||||||
cmd.Flags().StringVar(&flagTrackerType, "tracker-type", "", "Filter selected patterns by tracker type")
|
cmd.Flags().StringVar(&flagTrackerType, "tracker-type", "", "Filter selected patterns by tracker type")
|
||||||
cmd.Flags().StringVar(&flagKeyword, "keyword", "", "Filter selected patterns by a pattern/description substring")
|
cmd.Flags().StringVar(&flagKeyword, "keyword", "", "Filter selected patterns by a pattern/description substring")
|
||||||
cmd.Flags().StringVar(&flagState, "state", "", "Filter selected patterns by enrichment state (queued, enriched, unenriched)")
|
cmd.Flags().StringVar(&flagState, "state", "", "Filter selected patterns by enrichment state (queued, enriched, unenriched)")
|
||||||
|
cmd.Flags().BoolVar(&flagWithoutDescription, "without-description", false, "Only patterns with a blank description")
|
||||||
cmd.Flags().IntVar(&flagConcurrency, "concurrency", 4, "Number of patterns to enrich in parallel (sync mode)")
|
cmd.Flags().IntVar(&flagConcurrency, "concurrency", 4, "Number of patterns to enrich in parallel (sync mode)")
|
||||||
cmd.Flags().BoolVar(&flagResetEnriched, "reset-enriched", true, "Clear enriched_at so terminal rows are re-processed")
|
|
||||||
cmd.Flags().BoolVar(&flagDryRun, "dry-run", false, "Print the selected patterns without enriching")
|
cmd.Flags().BoolVar(&flagDryRun, "dry-run", false, "Print the selected patterns without enriching")
|
||||||
cmd.Flags().BoolVar(&flagYes, "yes", false, "Skip confirmation")
|
cmd.Flags().BoolVar(&flagYes, "yes", false, "Skip confirmation")
|
||||||
cmd.Flags().BoolVar(&flagEnqueue, "enqueue", false, "Arm the async enrichment worker instead of running the agent in-process")
|
cmd.Flags().BoolVar(&flagEnqueue, "enqueue", false, "Arm the async enrichment worker instead of running the agent in-process")
|
||||||
@@ -86,6 +86,7 @@ func newCmdReenrich(f *cmdutil.Factory) *cobra.Command {
|
|||||||
flagTrackerType,
|
flagTrackerType,
|
||||||
flagKeyword,
|
flagKeyword,
|
||||||
flagState,
|
flagState,
|
||||||
|
flagWithoutDescription,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -117,7 +118,7 @@ func newCmdReenrich(f *cmdutil.Factory) *cobra.Command {
|
|||||||
func(ctx context.Context, tx pg.Tx) error {
|
func(ctx context.Context, tx pg.Tx) error {
|
||||||
var ps coredata.CommonTrackerPatterns
|
var ps coredata.CommonTrackerPatterns
|
||||||
|
|
||||||
requeued, err = ps.RequestEnrichmentByIDs(ctx, tx, ids, flagResetEnriched)
|
requeued, err = ps.RequestEnrichmentByIDs(ctx, tx, ids)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
@@ -159,15 +160,16 @@ func newCmdReenrich(f *cmdutil.Factory) *cobra.Command {
|
|||||||
// resolveReenrichIDs turns the selection flags into the set of common
|
// resolveReenrichIDs turns the selection flags into the set of common
|
||||||
// tracker pattern IDs to re-enrich. Exactly one selection anchor must be
|
// tracker pattern IDs to re-enrich. Exactly one selection anchor must be
|
||||||
// provided: --id, --linked-banner, --linked-org, or --common-third-party.
|
// provided: --id, --linked-banner, --linked-org, or --common-third-party.
|
||||||
// The --tracker-type, --keyword, and --state flags further narrow the
|
// The --tracker-type, --keyword, --state, and --without-description flags
|
||||||
// anchor's result, except with --id, where the listed patterns are used
|
// further narrow the anchor's result, except with --id, where the listed
|
||||||
// verbatim.
|
// patterns are used verbatim.
|
||||||
func resolveReenrichIDs(
|
func resolveReenrichIDs(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
pgClient *pg.Client,
|
pgClient *pg.Client,
|
||||||
rawIDs []string,
|
rawIDs []string,
|
||||||
linkedBanner, linkedOrg, commonThirdParty string,
|
linkedBanner, linkedOrg, commonThirdParty string,
|
||||||
trackerType, keyword, state string,
|
trackerType, keyword, state string,
|
||||||
|
withoutDescription bool,
|
||||||
) ([]gid.GID, error) {
|
) ([]gid.GID, error) {
|
||||||
anchors := 0
|
anchors := 0
|
||||||
|
|
||||||
@@ -205,7 +207,7 @@ func resolveReenrichIDs(
|
|||||||
err := pgClient.WithConn(
|
err := pgClient.WithConn(
|
||||||
ctx,
|
ctx,
|
||||||
func(ctx context.Context, conn pg.Querier) error {
|
func(ctx context.Context, conn pg.Querier) error {
|
||||||
filter, err := buildReenrichFilter(trackerType, keyword, state)
|
filter, err := buildReenrichFilter(trackerType, keyword, state, withoutDescription)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -270,7 +272,7 @@ func resolveReenrichIDs(
|
|||||||
return ids, nil
|
return ids, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildReenrichFilter(trackerType, keyword, state string) (*coredata.CommonTrackerPatternFilter, error) {
|
func buildReenrichFilter(trackerType, keyword, state string, withoutDescription bool) (*coredata.CommonTrackerPatternFilter, error) {
|
||||||
filter := coredata.NewCommonTrackerPatternFilter()
|
filter := coredata.NewCommonTrackerPatternFilter()
|
||||||
|
|
||||||
if trackerType != "" {
|
if trackerType != "" {
|
||||||
@@ -295,6 +297,10 @@ func buildReenrichFilter(trackerType, keyword, state string) (*coredata.CommonTr
|
|||||||
filter.WithState(&st)
|
filter.WithState(&st)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if withoutDescription {
|
||||||
|
filter.WithDescribed(new(false))
|
||||||
|
}
|
||||||
|
|
||||||
return filter, nil
|
return filter, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user