Добрый день. 

Глобальный поиск и дедубликация ранее корректно работал на версии 2.0, после перевода его на 3.0, стал странно работать.

В системе есть раздел Purchase в нем порядка 25 млн записей. 

Глобальный поиск его судя по всему не проиндексировал, поиск по нему не происходит, хотя я принудительно пытаюсь его проиндексировать через 

/indexation/SiteName/Purchase/reindex/full мне в ответе приходит ОК, но ничего не происходит. 

 После запуска дедубликации по этому разделу она в базе mongo сразу стает завершенной без ошибок, а в интерфейсе остается на 0%. 

 По базовому разделу контакты дедубликация проходит тоже частично успешно, находит не все дубли. В mongo пишет, что обработано меньше записей, чем должно.

В mongo залазил согласно https://community.terrasoft.ua/articles/kak-proverit-nalichie-zapuschen…



 Ошибок по логам контейнеров не нашел. Подскажите может, кто-то сталкивался с такой проблемой, возможно есть дополнительные настройки?  Спасибо.

Нравится

2 комментария

Добрый день, Владимир!

 

Возможно, очередь не долшла к записям из этого раздела.

Полная переидексация для БД только в разделе Purchase может проходить достаточно долго.

Можно посмотреть значения колонки LastIndexeOn для раздела Purchase в таблице IndexingEntity в базе глобального поиска Postgres. Когда индексация дойдет к этому разделу значения из этой колонки начнет расти и можно будет поискать записи после завершения индексации раздела.

 

Как узнать завершилась ли индексация глобального поиска в on-site?

 

В БД глобального поиска, есть таблица IndexingEntity, которая отвечает за настройки индексации для каждой отдельной сущности, например Контакт, Средства связи контакта и т.д.

В ней есть 2 колонки, которые важны для понимания завершилась ли первичная индексация или нет:

  • LastIndexedOn - дата последней итерации индексации.

  • InProcess - в процессе ли индексация (одной итерации) по текущей сущности.

Индексация завершилась для конкретной сущности, лишь тогда, когда LastIndexedOn = дата подключения сайта к ГП и в InProcess установлено значение “false“.

Полностью индексация завершена, когда для всех записей из таблицы "IndexingEntity" значения в LastIndexedOn и InProcess установлены аналогично описанию выше.

Порядок настройки

  1. Зайти в контейнер с БД глобального поиска.

     

    docker exec -it gs-postgres bash

  2. Подключиться к БД глобального поиска.

     

    psql -d postgres -U postgres

  3. Выбрать, все записи из таблицы IndexingEntity.

     

    SELECT "EntityName", "LastIndexedOn", "InProcess" FROM "IndexingEntity";

 

P.S. Планировщик (который ответственный за первичную индексацию) запускается раз в 50 дней, таким образом доиндексирует\актуализирует необходимое.

То есть, это к тому, что каждые 50 дней эта дата будет обновляться.

Жмурко Сергей,

Спасибо за совет. Таблица показала, что LastIndexedOn везде пусто и InProcess везде false. То-есть индексация совсем не начиналась, хотя по контактам даже дубли находит. В логах контейнера с прогрессом были ошибки по вставке дублей в эту таблицу. Таблицу очистил попробую перезапустить все.

Показать все комментарии

В ходе работы с сервисом Дедупликации на основе глобального поиска может возникнуть проблема с зависанием процесса поиска дублей на уровне сервиса.

Зависание процесса характеризуется отсутствием результатов поиска длительное время и ограничением запуска повторной итерации поиска.



Для того чтобы завершить зависшую задачу в On-Site вам потребуется:



1. Зайти на сервер, где развернут сервис массового поиска дублей.

2. Зайти в docker-контейнер с базой MongoDB. В консоли выполнить команду:

docker exec -it dd-mongodb bash



3. Подключиться к MongoDB. В консоли выполнить команду:

mongo



4. Подключиться к базе, в которой храниться вся информация о задачах массового поиска дублей.

В консоли выполнить команду:

use dup-bulk-deduplication



5. Выбрать все задачи, которые в данный момент находятся в процессе.

В консоли выполнить команду:

db.getCollection('DeduplicationTaskEntity').find({Status: 2}).pretty()



В результате выполнения этой команды можно увидеть один или больше JSONобъектов, которые описывают запущенные задачи по поиску дублей.

JSON(ы) выглядят примерно так:



{ "_id" : UUID("450da7fb-9ac5-49c5-a146-feebc3482b2e"),

"IsActual" : true,

"TokenId" : "3a868426cf95283bd0b51ef7776337ed",

"ElasticIndexName" : "EntityName",

"SourceEntityName" : "IndexName",

"TotalRecordsCount" : NumberLong(0),

"ProcessedRecordsCount" : NumberLong(0),

"MaxDuplicatesPerRecord" : null,

"StartedOn" : ISODate("2021-01-13T09:31:16.269Z"),

"FinishedOn" : null,

"FailReason" : null,

"Status" : 2,

"Rules" : [

{

"_t" : "DeduplicationRuleEntity",

"Columns" : [

"#Column"

]

}

]

}



где,



Изображение удалено.

 

Обычно задачи зависают из-за того, что количество обработанных записей меньше, чем общее количество записей в разделе (ProcessedRecordsCount < TotalRecordsCount), при этом больше нет под-задач на обработку отдельной записи из раздела, то есть часть записей останется не обработанной. На данный момент нет ответа на вопрос, куда пропадают под-задачи на обработку отдельной записи из раздела. Эта проблема находиться в проработке.



6. Необходимо завершить одну (или несколько) зависшую задачу:

  •  Если необходимо завершить ОДНУ какую-то конкретную задачу (в случае, если есть одна зависшая задача, а вторая была недавно запущена и она еще действительно находиться в процессе), то нужно скопировать ID этой задачи и выполнить следующую команду:

getCollection('DeduplicationTaskEntity').updateOne({ _id: UUID("450da7fb9ac5-49c5-a146-feebc3482b2e")}, { $set: { Status: NumberInt(5) } })

 

           Если все выполнено правильно, то результат выполнения команды будет следующий:

{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }

 

  • Если необходимо просто завершить ВСЕ зависшие задачи:

    db.getCollection('DeduplicationTaskEntity').updateMany({ Status: 2}, { $set: { Status: NumberInt(5) } })



    Если все выполнено правильно, то результат выполнения команды будет следущий (где N - количество обновленных задач):

    { "acknowledged" : true, "matchedCount" : N, "modifiedCount" : N }

Нравится

Поделиться

0 комментариев
Показать все комментарии

Добавляю в игнор лист по кнопке "Не считать дублями".

Но что делать если нажал нечаянно и хочу вернуть обратно?

Нравится

2 комментария

Удалить запись из таблицы AccountDuplicateSearchGroupExclusions.

Василий, решение вашего запроса зависит от механизма дедупликации, который используется на сайте.

Для механизма поиска дублей на хранимых процедурах достаточно удалить записи  из таблиц AccountDuplicateSearchGroupExclusions/ContactDuplicateSearchGroupExclusions для очистки всех записей, которые были помечены как "Не считать дублями".

Для механизма поиска дублей с использованием сервиса дедупликации ( детальнее в статье https://academy.terrasoft.ua/docs/user/ustanovka_i_administrirovanie/ra…) для сброса признаков "Не являются дублями" всех помеченных пачек дублей на сервисе дедупликации необходимо почистить таблицу UniqueEntity в mongodb. 

Показать все комментарии

Добрый день, при попытке слияния двух контаков, если у проигравшего есть заказ, то процесс дедупликации падает с ошибкой: 

System.Data.SqlClient.SqlException (0x80131904): Конфликт инструкции DELETE с ограничением REFERENCE "FKZt10BIrUNMXjPYmQeSNwKs8aI". 

Конфликт произошел в базе данных "ClarinsInstall", таблица "dbo.Order", column 'ContactId'.

При отладке не увидела ContactId, среди ключей таблицы Order, по которым идет перепривязка данных (есть только CreatedById и OwnerId),

подскажите, с чем это может быть вызвано?

Нравится

3 комментария
Лучший ответ

Зверев Александр пишет:

Проверьте Order в дизайнере объектов, там должно быть такое справочное поле. А если нет, то было и его удалили в объекте, но по какой-то причине осталось в базе (возможно, объект не скомпилировали).

Если проблема, действительно, в этом, то нужно не выполнять обновление конкретной записи в Order, а определиться с необходимостью наличия поля Contact в Order и в зависимости от принятого решения либо добавить в entity schema Order данное поле и скомпилировать схему, если его нет, либо удалить из таблицы в базе данных, если оно не нужно.

Иначе проблема может воспроизвестись при следующем слиянии дублей.

Это как раз и значит наличие записи в Order, ссылающееся полем ContactId на сливаемый контакт. Проверьте Order в дизайнере объектов, там должно быть такое справочное поле. А если нет, то было и его удалили в объекте, но по какой-то причине осталось в базе (возможно, объект не скомпилировали). В таком случае, если есть возможность, подключитесь к БД, найдите эту запись и замените значение ContactId на null.

Зверев Александр пишет:

Проверьте Order в дизайнере объектов, там должно быть такое справочное поле. А если нет, то было и его удалили в объекте, но по какой-то причине осталось в базе (возможно, объект не скомпилировали).

Если проблема, действительно, в этом, то нужно не выполнять обновление конкретной записи в Order, а определиться с необходимостью наличия поля Contact в Order и в зависимости от принятого решения либо добавить в entity schema Order данное поле и скомпилировать схему, если его нет, либо удалить из таблицы в базе данных, если оно не нужно.

Иначе проблема может воспроизвестись при следующем слиянии дублей.

Кстати, не уверен, что повторное добавление поля в объект пройдёт успешно без последствий. У колонки в базе прописывается GUID в Extended Properties, он будет уже другим.

Показать все комментарии

Подскажите, пожалуйста, как можно настроить собственное правило поиска дубликатов среди контрагентов.

BPM Online 7.12

СУБД Oracle 11g

Проблема в том, что большинство инструкций относятся к MS SQL. В Oracle просто не вижу большинство указанных хранимых процедур. Плюс просто не вижу раздела "Правила поиска дубликатов" в Дизайнере системы. Не вижу в БД процедур типа "tsp_FindAccountDuplicateByName", процедура tsp_FindAccountSimilarRecords есть, но там пустышка.

Если я правильно понял, то глобальный поиск дубликатов пока недоступен для Oracle. Нужно хотя бы настроить локальный поиск дубликатов. 

Изменение пакета tspkg_DuplicatesSearch (функции fn_GetAccountDuplicates и процедуры tsp_SearchForAccountDuplicates) результата не дало. 

Вторая проблема: в стандарте вижу, что дубликат проверяется по Name(по крайней мере одно из правил) при изменении карточка контрагента. При создании нового контрагента эта же логика почему-то не работает и можно легко создать дубликаты.

Нравится

6 комментариев

Проверка на дубли при сохранении через миникарточку появилась в 7.12.3. В версии 7.12.3 появился поиск дублей на основании правил для Oracle. В будущих релизах планируется массовая дедупликация для данной СУБД + пользовательская настройка правил + уже можно технически с версии 7.12.3 для новой дедупликации добавить новое правило. Инструкция тут.

Зверев Александр,

Здравствуйте, Александр. 

Спасибо за информацию. Один уточняющий вопрос. У нас на DEV не настроен GlobalSearch (BPM развернут on-site). Однако дедубликация по name срабатывает. Как это может быть?

Видимо, это предыдущая версия, без глобального поиска. Новый то добавили только в 7.12.3:

Для БД Oracle, появилась возможность поиска дублей лидов, а также локального поиска дублей контактов и контрагентов при сохранении. Базовый набор правил поиска можно включать по ссылке “Правила поиска дублей” в дизайнере системы. Для работы поиска дублей на Oracle необходимо настроить глобальный поиск и включить функциональность “ESDeduplication”.

Добрый день. Апдейт на 7.12.3 провели. Global Serach и ESDeduplication включили, правило новое настроили. Видим, что оно работает корректно в миникарточке.

НО при сохранении/изменении в обычной карточке поиск дублей не происходит. Этот функционал для Oracle еще не реализован?

P.S. Стандартные правила также не работают при сохранении/изменении через основную карточку.

Вторая ссылка из моего верхнего комментария уже недоступна, хотя раньше точно была. Видимо, что-то в поддержке работы с Oracle ещё меняют, лучше ещё подождать.

Понятно. Спасибо

Показать все комментарии

Коллеги, выручайте. У меня были записи в разделе, которые создали разные контакты, но данные контакты по факту являются дубликатами.

Сделал поиск дубликатов для контактов, объединил найденные дубликаты. 



И получилось так, что у части записей затерлось поле "Создал", select возвращает данное поле со старым id создавшего, которого по факту уже нет так-как он объединился.



Как вернуть все обратно? Если возможность посмотреть логи дубликатов?



Я ожидал, что после объединения дубликатов, система сама перезапишет во всех записях поле создал на новый id.

Нравится

1 комментарий

Добрый день!

 

Дедупликация записи - это не создание новой.

Фактически, Вы удаляете одну из записей, и обновляете значения оставшейся.



Вернуть результат дедупликации пользовательскими средствами нельзя.

Вы можете поднять бэкап БД до обновления и перенести значения CreatedBy при помощи запроса в БД.

Показать все комментарии

В продолжение данного топика 

Правило дедубликации только по телефону не работает. Более того, методом научного тыка было обнаружено следующее:

1) Мы создали правило поиска по телефону и ещё одному полю UsrDedub (по аналогии правило поиска по названию и телефону).

2) Сделали значение UsrDedub = 1 в нескольких контрагентах (около 20). В лиде UsrDedub также = 1. Правило отработало корректно.

3) Сделали значение UsrDedub = 1 для всех контрагентов (около 7 500). Правило работать перестало.

4) Изменили параметр @offsetLimit в SQL запросе tsp_FindAccountSimilarRecords с 200 на 7500. Правило вновь стало работать.

Отсюда мы сделали вывод - правило поиска по телефону отрабатывает только по коллекции контрагентов, которые уже отобраны каким либо правилом поиска дублей.

Копаем дальше, но может кто-то может подсказать:

1) Насколько изменение @offsetLimit может быть критичным для быстродействия системы. Изменение до 10 000 визуально никаки систему не загрузили.

2) Как заставить правило поиска похожих контрагентов по телефону из лида работать самостоятельно, без дополнительных правил поиска.

3) Либо если он работает в паре с другим правилом - в первую очередь проводить поиск именно по телефону?

Нравится

2 комментария

Оказалось, что именно низкий @offsetLimit не позволяет правилу поиска похожих контрагентов по телефону отрабатывать корректно индивидуально. Чем чревато увеличение этого значения - пока не знаю.

Здравствуйте!

1. Если будет слишком большое количество записей, то вполне возможен отвал запроса по timeout.

2, 3.  Для того, чтобы правило поиска похожих контрагентов в лидах работало отдельно, необходимо в хранимой процедуре tsp_FindAccountSimilarRecords изменить блок "IF @execStmt IS NOT NULL..."  на:

               SET @detailsSelectQuery = N'SELECT TOP '+ CAST(@offsetLimit as NVARCHAR) +

                ' ' + @queryColumnName + CHAR(10) + 

                'FROM ' + CHAR(10) + @schemaName + CHAR(10) +

                'WITH (NOLOCK) ' + CHAR(10) +

                'WHERE 1=1 ';

                IF @execStmt IS NOT NULL

                BEGIN

                    SET @detailsSelectQuery = 

                    @detailsSelectQuery + CHAR(10) + 'AND' + CHAR(10) + @queryColumnName + CHAR(10) + ' IN ('    + @execStmt + ')';

                END

                IF @equalQueryConditions IS NOT NULL

                BEGIN

                    SET @detailsSelectQuery = @detailsSelectQuery + CHAR(10) + 

                    @equalQueryConditions;

                END

                IF @inQueryConditions IS NOT NULL

                BEGIN

                    SET @detailsSelectQuery = @detailsSelectQuery + CHAR(10) + @inQueryConditions;

                END

                IF @detailsSelectQuery IS NOT NULL

                BEGIN

                    INSERT INTO @resultIdsTable

                    EXEC sp_executesql @detailsSelectQuery;

                END

Показать все комментарии

Кейс следующий: сделать правило дедубликации в разделе лиды по похожим контрагентам с проверкой ТОЛЬКО по телефону. Базовое правило не подходит, поскольку проверяет по названию И телефону.

Добавил правило в DuplicatesRule, добавил процедуру поиска с помощью SQL запроса (см. AccountPhoneRuleUsr). Ничего не выходит. Что интересно, если убрать из базового правила (phoneAndAccountNameRule) упоминание поиска по названию, то он тоже перестаёт отрабатывать в принципе. Такое ощущение, что где-то прописано, что поиск по телефону работает только в паре с каким-то совпадением.

Кто-нибудь сталкивался с данной задачкой?

IF(OBJECT_ID('dbo.tsp_FindAccountSimilarRecords','P')) IS NOT NULL
	DROP PROCEDURE dbo.tsp_FindAccountSimilarRecords
GO
 
CREATE PROCEDURE tsp_FindAccountSimilarRecords (@primaryColumnValue uniqueidentifier, @rawXMLConfig nvarchar(MAX), @offsetLimit int = 200)
AS 
 
 
DECLARE @parsedConfig TABLE (
	SchemaName nvarchar(128),
	ParentShemaName nvarchar(128) NULL,
	ColumnName nvarchar(128),
	ColumnValue nvarchar(4000),
	ColumnValueTypeId nvarchar(128)
 );
 
DECLARE @accountRulesConfig TABLE (
	RuleId uniqueidentifier, 
	SchemaName sysname,
	ParentSchemaName sysname NULL,
	ColumnName sysname, 
	NormalizeFnPattern nvarchar(4000),
	CleanDataSchemaName sysname NULL);
 
DECLARE @xmlBody xml;
 
DECLARE @webAndAccountNameRule uniqueidentifier = 'd3607fd4-8303-40ae-b66e-000000000013'	,
		@phoneAndAccountNameRule uniqueidentifier = 'd3607fd4-8303-40ae-b66e-000000000014'	,
		@cityAndAccountNameRule uniqueidentifier = 'd3607fd4-8303-40ae-b66e-000000000015'	,
		@countryAndAccountNameRule uniqueidentifier = 'd3607fd4-8303-40ae-b66e-000000000016'	,
		@AccountNameRule uniqueidentifier = 'd3607fd4-8303-40ae-b66e-000000000017'	,
		@AccountPhoneRuleUsr uniqueidentifier = '778e768d-3941-4461-8954-59702c1f1fab'	,
		@AccountInnRule uniqueidentifier = '1470da34-31ae-4da5-b6c8-9410751133a4'	;
 
DECLARE @leadSchemaUId uniqueidentifier = '41AF89E9-750B-4EBB-8CAC-FF39B64841EC' ;
 
DECLARE @accountSchemaName sysname = 'Account',
		@accountCleanDataSchemaName sysname = 'VwAccountCleanDataValues',
		@accountCommunicationSchemaName sysname = 'AccountCommunication',
		@accountCommunicationCleanDataSchemaName sysname = 'VwAccountCommunicationCleanDataValues',
		@accountAddressSchemaName sysname = 'AccountAddress';
 
DECLARE @accountNameColumn sysname = 'Name',
		@accountInnColumn sysname = 'UsrINN',
		@accountCommunicationColumn sysname = 'Number',
		@accountCommunicationPhoneColumn sysname = 'SearchNumber',
		@accountCountryColumn sysname = 'CountryId',
		@accountCityColumn sysname = 'CityId',
		@communicationTypeIdColumn sysname = 'CommunicationTypeId';
 
DECLARE @resultIdsTable TABLE (Id uniqueidentifier);
 
DECLARE @phoneCommunicationTypeTable TABLE (Id uniqueidentifier);
 
DECLARE @preStmtValues TABLE (
	ColumnName sysname NOT NULL,
	ColumnValue nvarchar (4000) NULL,
	SchemaName sysname NOT NULL,
	ColumnValueTypeId NVARCHAR(128)
);
 
 
DECLARE @emailNormalizePattern nvarchar(50) = N'0-9a-zа-я@_.',
		@nameNormalizePattern nvarchar(50) = N'0-9a-zа-я',
		@normalizedFnSelectStmt nvarchar(250),
		@innNormalizePattern nvarchar(12) = N'0-9',
		@normalizedFnValueStmt nvarchar(250);
 
DECLARE @execStmt nvarchar(MAX),
		@baseNormalizeFn sysname = 'dbo.fn_NormalizeString',
		@phoneNormalizeFn sysname = 'dbo.fn_ExtractDigitLimitFromNumber',
		@webNormalizeFn sysname = 'dbo.fn_ExtractDomainFromUrl';
 
DECLARE @ruleId uniqueidentifier,
		@countDetailValues int = 0;
 
DECLARE @inQueryConditions nvarchar(MAX),
		@equalQueryConditions nvarchar(MAX),
		@schemaName sysname,
		@queryColumnName nvarchar(128);
 
BEGIN
 
 
	SET @xmlBody  = CAST(@rawXMLConfig AS XML);
 
	INSERT INTO @phoneCommunicationTypeTable
	VALUES('0DA6A26B-D7BC-DF11-B00F-001D60E938C6') ,
		('3DDDB3CC-53EE-49C4-A71F-E9E257F59E49') ,
		('D4A2DC80-30CA-DF11-9B2A-001D60E938C6') ,
		('2B387201-67CC-DF11-9B2A-001D60E938C6') ,
		('6A3FB10C-67CC-DF11-9B2A-001D60E938C6') ,
		('E9D91E45-8D92-4E38-95A0-EF8AA28C9E7A') 
 
 
	INSERT INTO @accountRulesConfig (RuleId, SchemaName, ParentSchemaName, ColumnName, NormalizeFnPattern, CleanDataSchemaName)
	VALUES 	(@webAndAccountNameRule, @accountCommunicationSchemaName, @accountSchemaName, @accountCommunicationColumn,  @webNormalizeFn + '(N##VALUE##)', @accountCommunicationCleanDataSchemaName),
			(@webAndAccountNameRule, @accountSchemaName, NULL, @accountNameColumn,  @baseNormalizeFn + '(N##VALUE##,N''' + @nameNormalizePattern + ''')',  @accountCleanDataSchemaName),
			(@phoneAndAccountNameRule, @accountCommunicationSchemaName, @accountSchemaName, @accountCommunicationPhoneColumn,  @phoneNormalizeFn + '(##VALUE##)', @accountCommunicationCleanDataSchemaName),
			(@phoneAndAccountNameRule, @accountSchemaName, NULL, @accountNameColumn,  @baseNormalizeFn + '(N##VALUE##,N''' + @nameNormalizePattern + ''')', @accountCleanDataSchemaName),
			(@cityAndAccountNameRule, @accountAddressSchemaName, @accountSchemaName, @accountCityColumn, NULL, NULL),
			(@cityAndAccountNameRule, @accountSchemaName, NULL, @accountNameColumn, @baseNormalizeFn + '(N##VALUE##,N''' + @nameNormalizePattern + ''')', @accountCleanDataSchemaName),
			(@countryAndAccountNameRule, @accountAddressSchemaName, @accountSchemaName, @accountCountryColumn, NULL,NULL),
			(@countryAndAccountNameRule, @accountSchemaName, NULL, @accountNameColumn, @baseNormalizeFn + '(N##VALUE##,N''' + @nameNormalizePattern + ''')', @accountCleanDataSchemaName),
			(@AccountInnRule, @accountSchemaName, NULL, @accountInnColumn, @baseNormalizeFn + '(N##VALUE##,N''' + @innNormalizePattern + ''')', NULL),
			(@AccountPhoneRuleUsr, @accountCommunicationSchemaName, @accountSchemaName, @accountCommunicationPhoneColumn,  @phoneNormalizeFn + '(##VALUE##)', NULL),
			(@AccountNameRule, @accountSchemaName, NULL, @accountNameColumn, @baseNormalizeFn + '(N##VALUE##,N''' + @nameNormalizePattern + ''')', @accountCleanDataSchemaName);
 
	INSERT INTO @parsedConfig
	SELECT NULLIF(p.value('(./schemaName)[1]', 'VARCHAR(128)'),'') AS SchemaName,
		NULLIF(p.value('(./parentSchemaName)[1]', 'VARCHAR(128)'),'') AS ParentSchemaName,
		NULLIF(p.value('(./columnName)[1]', 'NVARCHAR(128)'),'') AS ColumnName,
		NULLIF(p.value('(./columnValue)[1]', 'NVARCHAR(4000)'),'') AS ColumnValue,
		NULLIF(p.value('(./typeId)[1]', 'NVARCHAR(128)'),'') AS ColumnValueTypeId
		FROM @xmlBody.nodes('/columns/item') t(p)
 
	UPDATE	@parsedConfig 
	SET ColumnValue = dbo.fn_GetPhoneNumberSearchForm(ColumnValue)
	WHERE ColumnName = @accountCommunicationPhoneColumn
 
	DECLARE activeRuleList CURSOR
	FOR SELECT Id from DuplicatesRule
		WHERE ObjectId = @leadSchemaUId
		AND Id IN (SELECT RuleId FROM @accountRulesConfig)
		AND isActive = 1;
 
	OPEN activeRuleList
	FETCH NEXT
		FROM activeRuleList INTO @ruleId 
 
	WHILE @@FETCH_STATUS = 0
	BEGIN
 
		SET @execStmt = NULL;
		SET @countDetailValues = 0;
		SET @equalQueryConditions = NULL;
		SET @inQueryConditions = NULL;
 
 
		IF EXISTS (SELECT NULL
			FROM @accountRulesConfig config
			LEFT JOIN @parsedConfig parsed
			ON config.ColumnName = parsed.ColumnName
			AND config.SchemaName = parsed.SchemaName
			WHERE parsed.ColumnName IS NULL 
			AND config.RuleId = @ruleId)
		BEGIN 
			FETCH NEXT
			FROM activeRuleList INTO @ruleId
			CONTINUE
		END
		ELSE
		BEGIN	
			IF EXISTS (
				SELECT NULL
					FROM @parsedConfig parsed, @accountRulesConfig config
					WHERE parsed.ColumnName =config.ColumnName
					AND parsed.SchemaName = config.SchemaName
					AND config.ParentSchemaName IS NULL
					AND parsed.ColumnValue IS NULL
					AND config.RuleId = @ruleId)
			BEGIN
				FETCH NEXT
					FROM activeRuleList INTO @ruleId
				CONTINUE
			END
			ELSE
			BEGIN
				DELETE FROM @preStmtValues
				INSERT INTO @preStmtValues (ColumnName, ColumnValue, SchemaName)
				SELECT ISNULL(rulesCfg.CleanDataSchemaName, rulesCfg.SchemaName)+'.'+rulesCfg.ColumnName,
						CASE WHEN NormalizeFnPattern IS NOT NULL THEN 
							REPLACE(NormalizeFnPattern, '##VALUE##', QUOTENAME(parsedCfg.ColumnValue, ''''))
						ELSE QUOTENAME(parsedCfg.ColumnValue, '''') END ColumnValue, 
						ISNULL(rulesCfg.CleanDataSchemaName, rulesCfg.SchemaName)
					FROM @accountRulesConfig rulesCfg, 
						 @parsedConfig parsedCfg
					WHERE rulesCfg.ColumnName = parsedCfg.ColumnName
					AND rulesCfg.SchemaName = parsedCfg.SchemaName
					AND rulesCfg.ParentSchemaName IS NULL
					AND RuleId = @ruleId
 
				SET @queryColumnName = 'Id';
 
				SELECT TOP 1 @schemaName = SchemaName FROM @preStmtValues 
 
				SELECT DISTINCT @inQueryConditions = 
					' AND ' + ColumnName + ' IN (' + STUFF((SELECT ',' + ColumnValue FROM @preStmtValues f 
					WHERE f.ColumnName = t.ColumnName AND f.ColumnName IN (
						SELECT t.ColumnName 
							FROM @preStmtValues t 
						GROUP BY ColumnName HAVING COUNT(*) > 1)
					FOR XML PATH(''), TYPE).value('(./text())[1]','nvarchar(max)'), 1,1, '') +')' FROM @preStmtValues t
 
				SELECT DISTINCT @equalQueryConditions = 
					STUFF((SELECT ' AND ' 
							+ ColumnName + ' LIKE ' 
							+ ColumnValue FROM @preStmtValues f
					WHERE f.ColumnName IN (
						SELECT t.ColumnName 
							FROM @preStmtValues t 
						GROUP BY ColumnName HAVING COUNT(*) = 1) 
					FOR XML PATH(''), TYPE).value('(./text())[1]','nvarchar(max)'), 1,1, '')
 
				SET @execStmt = 
					N'SELECT TOP '+CAST(@offsetLimit as NVARCHAR)+' '+@queryColumnName + CHAR(10) + 
					'FROM '+ CHAR(10) +
					@schemaName + CHAR(10) +
					'WITH (NOLOCK) ' + CHAR(10) +
					'WHERE 1=1'+ CHAR(10);
 
				IF @equalQueryConditions IS NOT NULL
				BEGIN
					SET @execStmt = @execStmt + CHAR(10) + 
					@equalQueryConditions
				END
 
				IF @inQueryConditions IS NOT NULL
				BEGIN
					SET @execStmt = @execStmt + CHAR(10) + 
					@inQueryConditions
				END
 
 
				IF EXISTS (SELECT NULL FROM @accountRulesConfig 
								WHERE RuleId = @ruleId
								AND ParentSchemaName IS NOT NULL)
				BEGIN
					IF EXISTS (
						SELECT NULL
						 FROM @parsedConfig parsed, @accountRulesConfig config
							WHERE parsed.ColumnName =config.ColumnName
								AND parsed.SchemaName = config.SchemaName
								AND parsed.ParentShemaName = config.ParentSchemaName
								AND parsed.ColumnValue IS NOT NULL
								AND config.RuleId = @ruleId)
					BEGIN
 
						DELETE FROM @preStmtValues
						INSERT INTO @preStmtValues (ColumnName, ColumnValue, SchemaName, ColumnValueTypeId)
						SELECT ISNULL(rulesCfg.CleanDataSchemaName, rulesCfg.SchemaName)+'.'+rulesCfg.ColumnName, 
							CASE WHEN NormalizeFnPattern IS NOT NULL THEN 
							REPLACE(NormalizeFnPattern, '##VALUE##', QUOTENAME(parsedCfg.ColumnValue, ''''))
							ELSE QUOTENAME(parsedCfg.ColumnValue, '''') END ColumnValue, 
							ISNULL(rulesCfg.CleanDataSchemaName, rulesCfg.SchemaName),
							ColumnValueTypeId
							FROM @accountRulesConfig rulesCfg, 
								 @parsedConfig parsedCfg
							WHERE rulesCfg.ColumnName = parsedCfg.ColumnName
							AND rulesCfg.ParentSchemaName = parsedCfg.ParentShemaName
							AND rulesCfg.SchemaName = parsedCfg.SchemaName
							AND RuleId = @ruleId
 
 
						SET @queryColumnName = 'AccountId';
 
						IF EXISTS (
							SELECT NULL 
								FROM @phoneCommunicationTypeTable 
								WHERE Id in (SELECT ColumnValueTypeId FROM @preStmtValues f))
						BEGIN 
							INSERT INTO @preStmtValues (ColumnName, ColumnValue, SchemaName)
							SELECT @communicationTypeIdColumn, 
							'''' + CAST(Id AS NVARCHAR(50)) + '''', 
							(SELECT TOP 1 SchemaName FROM @preStmtValues)
							FROM @phoneCommunicationTypeTable
						END
						ELSE 
						BEGIN
							INSERT INTO @preStmtValues (ColumnName, ColumnValue, SchemaName)
							SELECT @communicationTypeIdColumn, 
							'''' + ColumnValueTypeId + '''',
							SchemaName FROM @preStmtValues
							WHERE ColumnValueTypeId IS NOT NULL
						END	
 
						SELECT TOP 1 @schemaName = SchemaName FROM @preStmtValues 
 
						SELECT DISTINCT @inQueryConditions = 
							' AND ' + ColumnName + ' IN (' + STUFF((SELECT ',' + ColumnValue FROM @preStmtValues f 
							WHERE f.ColumnName = t.ColumnName AND f.ColumnName IN (
								SELECT t.ColumnName 
									FROM @preStmtValues t 
								GROUP BY ColumnName HAVING COUNT(*) > 1)
							FOR XML PATH(''), TYPE).value('(./text())[1]','nvarchar(max)'), 1,1, '') +')' FROM @preStmtValues t
 
						SELECT DISTINCT @equalQueryConditions = 
							STUFF((SELECT ' AND ' 
									+ ColumnName + ' LIKE ' 
									+ ColumnValue FROM @preStmtValues f
							WHERE f.ColumnName IN (
								SELECT t.ColumnName 
									FROM @preStmtValues t 
								GROUP BY ColumnName HAVING COUNT(*) = 1) 
							FOR XML PATH(''), TYPE).value('(./text())[1]','nvarchar(max)'), 1,1, '')
 
						IF @execStmt IS NOT NULL
						BEGIN
							SET @execStmt = 
							N'SELECT TOP '+CAST(@offsetLimit as NVARCHAR)+' '+@queryColumnName + CHAR(10) + 
							'FROM ' + CHAR(10) + 
							@schemaName + CHAR(10) +
							'WITH (NOLOCK) ' + CHAR(10) +
							'WHERE '+ @queryColumnName + CHAR(10) + 
							' IN ('	+ @execStmt + ')';
 
							IF @equalQueryConditions IS NOT NULL
							BEGIN
								SET @execStmt = @execStmt + CHAR(10) + 
								@equalQueryConditions;
							END	
 
							IF @inQueryConditions IS NOT NULL
							BEGIN
								SET @execStmt = @execStmt + CHAR(10) + 
								@inQueryConditions;
							END	
 
							INSERT INTO @resultIdsTable
							EXEC sp_executesql @execStmt;
						END
					END
				END
				ELSE
				BEGIN
					INSERT INTO @resultIdsTable
					EXEC sp_executesql @execStmt;
				END
			END
		END
 
	FETCH NEXT
		FROM activeRuleList INTO @ruleId
	END
	CLOSE activeRuleList
	DEALLOCATE activeRuleList
 
	DELETE
		FROM @resultIdsTable
		WHERE Id = @primaryColumnValue
 
	SELECT DISTINCT TOP (@offsetLimit) Id 
		FROM @resultIdsTable
 
END

 

Нравится

3 комментария

Здравствуйте, Данил!

Кастомизация правил поиска похожих лидов осуществляется по инструкции ниже.

1. Необходимо добавить скриптом новое правило в таблицу DuplicatesRule.

Пример скрипта:

insert into DuplicatesRule

(Name, IsActive, ObjectId)

values

('Имя правила', 1, '41AF89E9-750B-4EBB-8CAC-FF39B64841EC')

 

2. Заместить хранимую процедуру tsp_FindAccountSimilarRecordsMSSQL (для примера поиска по контрагентам, по контактам соответственно tsp_FindContactSimilarRecordsMSSQL). Для этого необходимо скопировать весь код из tsp_FindAccountSimilarRecordsMSSQL и дублировать его в новый SQL Script.

3. Объявить своё правилj в блоке с остальными правилами, где указать id добавленного правила с пункта 1 (из таблицы DuplicatesRule) http://prntscr.com/e2m5wz

4. Аналогично существующим правилам, добавить и своё в @accountRulesConfig http://prntscr.com/e2m72y

Например, если правило только для Телефона, копируем выделенную строчку на скриншоте и заменяем название правила на кастомное: http://prntscr.com/i5yogj&nbsp;

5. Сохранить хранимую процедуру и выполнить установку в БД.

Если привязаться к Вашему коду, то ошибка вероятнее всего в п. 4. , т.к. правило определено неправильно: http://prntscr.com/i5yppg

 

Приятной работы

 

Пробовал и полностью скопировав это правило (если вы про отсутствие @accountCleanDataSchemaName в конце) - не работает.

Что интересно, если я прописываю правило с поиском по ИНН+Телефон, то поиск отрабатывает корректно - проверяет совпадение в обоих полях. Но как только пробую оставить ТОЛЬКО по телефону, то такая дедубликация не работает.

Здравствуйте!

Правила поиска дублей для похожих контрагентов/контактов в лиде сделаны таким образом, что нет возможности обращаться отдельно к таблице средств связи, по которой и происходит поиск только по телефону. Логика хранимых процедур была написана с учётом базовых правил, которые предполагают поиск похожих контактов/контрагентов только по правилам, которые включают поиск в таблице Account/Contact плюс таблица средств связи. А обращение только к таблице средств связи в текущей реализации хранимой процедуры не предусмотрено.

Для работы своего правила только по телефону или любого другого средства связи, необходимо внести изменения в хранимую процедуру tsp_FindAccountSimilarRecords, а именно вместо блока "IF @execStmt IS NOT NULL..."  (http://prntscr.com/ibe672) добавить код ниже:



               SET @detailsSelectQuery = N'SELECT TOP '+ CAST(@offsetLimit as NVARCHAR) +

                ' ' + @queryColumnName + CHAR(10) + 

                'FROM ' + CHAR(10) + @schemaName + CHAR(10) +

                'WITH (NOLOCK) ' + CHAR(10) +

                'WHERE 1=1 ';



                IF @execStmt IS NOT NULL

                BEGIN

                    SET @detailsSelectQuery = 

                    @detailsSelectQuery + CHAR(10) + 'AND' + CHAR(10) + @queryColumnName + CHAR(10) + ' IN ('    + @execStmt + ')';

                END



                IF @equalQueryConditions IS NOT NULL

                BEGIN

                    SET @detailsSelectQuery = @detailsSelectQuery + CHAR(10) + 

                    @equalQueryConditions;

                END



                IF @inQueryConditions IS NOT NULL

                BEGIN

                    SET @detailsSelectQuery = @detailsSelectQuery + CHAR(10) + @inQueryConditions;

                END



                IF @detailsSelectQuery IS NOT NULL

                BEGIN

                    INSERT INTO @resultIdsTable

                    EXEC sp_executesql @detailsSelectQuery;

                END

Показать все комментарии