Медленное выполнение USQL

Я создал простой скрипт для оценки между двумя строками. Ниже приведен код USQL и BackEnd .net.

CN_Matcher.usql:

REFERENCE ASSEMBLY master.FuzzyString;

@searchlog =
        EXTRACT ID int,
                Input_CN string,
                Output_CN string
        FROM "/CN_Matcher/Input/sample.txt"
        USING Extractors.Tsv();

@CleansCheck =
    SELECT ID,Input_CN, Output_CN, CN_Validator.trial.cleanser(Input_CN) AS Input_CN_Cleansed,
           CN_Validator.trial.cleanser(Output_CN) AS Output_CN_Cleansed
    FROM @searchlog;

@CheckData= SELECT ID,Input_CN, Output_CN, Input_CN_Cleansed, Output_CN_Cleansed,
                   CN_Validator.trial.Hamming(Input_CN_Cleansed, Output_CN_Cleansed) AS HammingScore,
                   CN_Validator.trial.LevinstienDistance(Input_CN_Cleansed, Output_CN_Cleansed) AS LevinstienDistance,
                   FuzzyString.ComparisonMetrics.JaroWinklerDistance(Input_CN_Cleansed, Output_CN_Cleansed) AS JaroWinklerDistance
                                       FROM @CleansCheck;

OUTPUT @CheckData
    TO "/CN_Matcher/CN_Full_Run.txt"
    USING Outputters.Tsv();

CN_Matcher.usql.cs:

using Microsoft.Analytics.Interfaces;
using Microsoft.Analytics.Types.Sql;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;

namespace CN_Validator
{
    public static class trial
    {

        public static string cleanser(string val)
        {
            List<string> wordsToRemove = "l.p. registered pc bldg pllc lp. l.c. div. national l p l.l.c international r. limited school azioni joint co-op corporation corp., (corp) inc., societa company llp liability l.l.l.p llc bancorporation manufacturing c dst (inc) jv ltd. llc. technology ltd., s.a. mfg rllp incorporated per venture l.l.p c. p.l.l.c l.p.. p. partnership corp co-operative s.p.a tech schl bancorp association lllp n r ltd inc. l.l.p. p.c. co district int intl assn. sa inc l.p co, co. division lc intl. lp professional corp. a l. l.l.c. building r.l.l.p co.,".Split(' ').ToList();
            return string.Join(" ", val.ToLower().Split(' ').Except(wordsToRemove));
        }

        public static int Hamming(string source, string target)
        {   
            int distance = 0;
            if (source.Length == target.Length)
            {
                for (int i = 0; i < source.Length; i++)
                {
                    if (!source[i].Equals(target[i]))
                    {
                        distance++;
                    }
                }
                return distance;
            }
            else { return 99999; }
        }

        public static int LevinstienDistance(string source, string target)
        {
            int n = source.Length;
            int m = target.Length;
            int[,] d = new int[n + 1, m + 1]; // matrix
            int cost; // cost
            // Step 1
            if (n == 0) return m;
            if (m == 0) return n;
            for (int i = 0; i <= n; d[i, 0] = i++) ;
            for (int j = 0; j <= m; d[0, j] = j++) ;
            for (int i = 1; i <= n; i++)
            {
                for (int j = 1; j <= m; j++)
                {
                    cost = (target.Substring(j - 1, 1) == source.Substring(i - 1, 1) ? 0 : 1);
                    d[i, j] = System.Math.Min(System.Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1),
                              d[i - 1, j - 1] + cost);
                }
            }
            return d[n, m];
        }

    }
}

Я запустил пробную партию со 100 входными данными, установил параллелизм равным 1 и приоритет равным 1000. Задание выполнено за 1,6 минуты.

Я хотел протестировать ту же задачу с 1000 входными данными и установить параллелизм равным 1, а приоритет равным 1000, и в соответствии с моими расчетами, поскольку это заняло 1,6 минуты для 100 входных данных, я думал, что это займет около 20 минут для 1000 входных данных, но он работал. более 50 минут, и я не заметил никакого прогресса.

Поэтому я добавил еще 100 входных заданий и протестировал их так же, как и в прошлый раз. Итак, я подумал об увеличении параллелизма, увеличил его до 3 и снова запустил, он не завершился даже через 1 час.

JOB_ID = 07c0850d-0770-4430-a288-5cddcfc26699

Основная проблема в том, что я не вижу ни прогресса, ни статуса.

Пожалуйста, дайте мне знать, если я делаю что-то не так.

Есть ли способ использовать конструктор в USQL? Поскольку, если я смогу это сделать, мне не нужно будет снова и снова выполнять одни и те же действия по очищению.


person The6thSense    schedule 10.11.2016    source источник


Ответы (2)


Я предполагаю, что вы используете синтаксис набора файлов для указания 1000 файлов? К сожалению, текущая реализация наборов файлов по умолчанию плохо масштабируется, и фаза компиляции (подготовки) займет много времени (как и выполнение). В настоящее время у нас есть лучшая реализация в предварительной версии. Не могли бы вы отправить мне письмо по адресу usql в Microsoft dot com, и я расскажу вам, как вы можете опробовать предварительную реализацию.

Спасибо, Майкл.

person Michael Rys    schedule 11.11.2016
comment
Привет, Майкл, это не 1000 файлов, это один файл с тысячами входных данных. Я отправлю вам письмо. Спасибо за ответ. - person The6thSense; 12.11.2016

Я рассмотрел более основанный на наборах способ сделать это. Например, вместо того, чтобы хранить слова для удаления в файле кода программной части, храните их в таблице U-SQL, чтобы их было легко добавить:

CREATE TABLE IF NOT EXISTS dbo.wordsToRemove
(
    word string,

    INDEX cdx_wordsToRemvoe CLUSTERED (word ASC) 
    DISTRIBUTED BY HASH (word)
);

INSERT INTO dbo.wordsToRemove ( word )
SELECT word
FROM (
VALUES
    ( "l.p." ),
    ( "registered" ),
    ( "pc" ),
    ( "bldg" ),
    ( "pllc" ),
    ( "lp." ),
    ( "l.c." ),
    ( "div." ),
    ( "national" ),
    ( "l" ),
    ( "p" ),
    ( "l.l.c" ),
    ( "international" ),
    ( "r." ),
    ( "limited" ),
    ( "school" ),
    ( "azioni" ),
    ( "joint" ),
    ( "co-op" ),
    ( "corporation" ),
    ( "corp.," ),
    ( "(corp)" ),
    ( "inc.," ),
    ( "societa" ),
    ( "company" ),
    ( "llp" ),
    ( "liability" ),
    ( "l.l.l.p" ),
    ( "llc" ),
    ( "bancorporation" ),
    ( "manufacturing" ),
    ( "c" ),
    ( "dst" ),
    ( "(inc)" ),
    ( "jv" ),
    ( "ltd." ),
    ( "llc." ),
    ( "technology" ),
    ( "ltd.," ),
    ( "s.a." ),
    ( "mfg" ),
    ( "rllp" ),
    ( "incorporated" ),
    ( "per" ),
    ( "venture" ),
    ( "l.l.p" ),
    ( "c." ),
    ( "p.l.l.c" ),
    ( "l.p.." ),
    ( "p." ),
    ( "partnership" ),
    ( "corp" ),
    ( "co-operative" ),
    ( "s.p.a" ),
    ( "tech" ),
    ( "schl" ),
    ( "bancorp" ),
    ( "association" ),
    ( "lllp" ),
    ( "n" ),
    ( "r" ),
    ( "ltd" ),
    ( "inc." ),
    ( "l.l.p." ),
    ( "p.c." ),
    ( "co" ),
    ( "district" ),
    ( "int" ),
    ( "intl" ),
    ( "assn." ),
    ( "sa" ),
    ( "inc" ),
    ( "l.p" ),
    ( "co," ),
    ( "co." ),
    ( "division" ),
    ( "lc" ),
    ( "intl." ),
    ( "lp" ),
    ( "professional" ),
    ( "corp." ),
    ( "a" ),
    ( "l." ),
    ( "l.l.c." ),
    ( "building" ),
    ( "r.l.l.p" ),
    ( "co.," )
) AS words(word);

Затем, чтобы провести сравнение, я разделил исходную фразу, удалил ненужные слова, а затем снова соединил фразу, примерно так:

//DECLARE @inputFile string = "input/input.csv"; // 500 companies, Standard & Poor 500 companies from wikipedia
DECLARE @inputFile string = "input/input2.csv"; // 850,000 companies, part 1 of extract from Companies House


@searchlog =
    EXTRACT id int,
            Input_CN string,
            Output_CN string
    FROM @inputFile
    USING Extractors.Csv(silent : true);
    //USING Extractors.Csv(skipFirstNRows:1);


// Split the input string to remove unwanted words
@Input_CN =
    SELECT id,
           new SQL.ARRAY<string>(Input_CN.Split(' ')) AS splitWords
    FROM @searchlog;


@Output_CN =
    SELECT id,
           new SQL.ARRAY<string>(Output_CN.Split(' ')) AS splitWords
    FROM @searchlog;


// Remove unwanted words from input string
@Input_CN =
    SELECT *
    FROM
    (
        SELECT o.id,
               x.splitWord.ToLower() AS splitWord
        FROM @Input_CN AS o
             CROSS APPLY
                 EXPLODE(splitWords) AS x(splitWord)
    ) AS y    
    ANTISEMIJOIN
        dbo.wordsToRemove AS w
    ON y.splitWord == w.word;

// Remove unwanted words from output string
@Output_CN =
    SELECT *
    FROM
    (
        SELECT o.id,
               x.splitWord.ToLower() AS splitWord
        FROM @Output_CN AS o
             CROSS APPLY
                 EXPLODE(splitWords) AS x(splitWord)
    ) AS y
    ANTISEMIJOIN
        dbo.wordsToRemove AS w
    ON y.splitWord == w.word;




// Put the input string back together again
@Input_CN =
    SELECT id,
           String.Join( " ", ARRAY_AGG (splitWord) ) AS Input_CN_Cleansed
    FROM @Input_CN
    GROUP BY id;


@Output_CN =
    SELECT id,
           String.Join( " ", ARRAY_AGG (splitWord) ) AS Output_CN_Cleansed
    FROM @Output_CN
    GROUP BY id;



@output =
    SELECT i.id,
           i.Input_CN_Cleansed,
           o.Output_CN_Cleansed,
           CN_Validator.trial.Hamming(i.Input_CN_Cleansed, o.Output_CN_Cleansed) AS HammingScore,
           CN_Validator.trial.LevinstienDistance(i.Input_CN_Cleansed, o.Output_CN_Cleansed) AS LevinstienDistance
    FROM @Input_CN AS i
         INNER JOIN
             @Output_CN AS o
         ON i.id == o.id;



OUTPUT @output
    TO "/output/output.csv"
    USING Outputters.Csv();

Я обнаружил, что производительность была аналогичной, но, возможно, дизайн более удобен в обслуживании. В любом случае мой код выполнялся всего за несколько минут с 850+ тыс. записей, а не 50+ минут, так что, возможно, была другая проблема. NB Мне не хватало библиотеки FuzzyString, поэтому я не включил ее в свой тест — это может объяснить разницу.

Если вы получите обновление по этому вопросу от Microsoft, отправьте ответ в этой теме и даже отметьте его как ответ, если хотите.

person wBob    schedule 19.11.2016
comment
Если я получу исправление по этой проблеме, я обязательно опубликую его здесь. Спасибо за обновление кода. Поскольку не рекомендуется нормализовать SQL, я думал сделать это в конце .net, но ваш код выглядит удобным для сопровождения, и похоже, что вы используете всю мощь USQL. - person The6thSense; 21.11.2016