Удалите re: etc из запроса SQL Linq

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

Если тема электронного письма включает что-то в формате номера тикета, я ищу по нему, и все готово. Это работает годами.

Теперь мы хотим найти по теме соответствующий заголовок билета.

Я нашел Удаление «RE:» (и т.п.) из темы электронной почты с помощью класса RegEx, который отлично подходит для удаления re: и т. д. из входящей темы. Но у нас есть случаи, когда название билета включает RE:. Я ожидаю, что он может включать FW: и FWD:, а также смешанные и строчные версии всех этих.

Какой самый чистый запрос Linq или SQL для поиска соответствия? Я знаком с Replace(). Могу ли я связать их вместе? Ужасно некрасиво связывать воедино 16 замен, чтобы поймать все версии case, но я полагаю, что мог бы с этим смириться.

И как производительность при этом? Полагаю, я могу ToLower обе стороны, и это должно работать? Это, вероятно, не повредило бы моему совпадению названий тем. Это до трех замен.

Я нашел одну страницу, на которой говорилось, что использование регулярных выражений в запросе приводит к извлечению всех данных, что может быть дорого. Это относится и к Remove? Я уже фильтрую по входящему адресу электронной почты, чтобы получить одного клиента, поэтому я не собираюсь использовать их для всей базы данных. Итак, может быть, регулярное выражение жизнеспособно?

Есть ли что-то лучше? Напоминаем, мы используем Entity Framework.

Спасибо

PS: я знаю, что некоторые простые предметы могут получить несколько обращений. «Ошибка» или «Проблема с электронной почтой». Я закажу по дате убывания и надеюсь, что поймаю большинство из них.

----- Редактировать: -----

Простите меня, я думал, что мое описание было довольно подробным. Это довольно хорошо сдерживаемая проблема. Другими словами, у меня есть несколько общих посторонних текстовых фрагментов в поле VARCHAR, и я ищу лучший способ поиска по этому полю, который игнорирует эти несколько общих текстовых фрагментов.

Вот текущее состояние моего метода FindExistingTicket(). Я начал фильтрацию по клиентам, но не закончил ее, когда увидел эти комментарии. (Меня не было на рабочем месте пару часов.)

    /// <summary>
    /// Given a from address and a subject, see if we can find a ticket to match.
    /// to match.  Either the formatted ticket number is in the subject.
    /// Or, the subject is identical to a ticket title.
    /// </summary>
    /// <param name = "from">The From address.</param>
    /// <param name = "subject">The subject string.</param>
    /// <returns>The ticket found, or null.</returns>
 public Ticket FindExistingTicket(string from, string subject)
 {
    Ticket ticket = null;

    // If the subject is null then there's not going to be a match.
    if (subject == null)
    {
        return null;
    }

    // First look for a formatted ticket number.
    Match m = TicketNumRegex.Match(subject);

    if (m.Success)
    {
        // Make sure a ticket with that number actually exists.
        ticket = db.Tickets.Where(a => a.TicketNumber == m.Value).FirstOrDefault();
    }
    // If we have a ticket, then we're done.
    if (ticket != null) return ticket;

    // Check to see if we know this email address
    Contact contact = db.Contacts.Where(a => a.ContactStatu.Status.Equals("Active") && a.email.ToLower().Contains(from)).FirstOrDefault();
    if (contact != null)
    {
        Client client = db.Clients.Where(a => a.id == contact.customer_id).FirstOrDefault();

        // Search for a ticket where the Subject matches the Title.
        // First, strip off any re: or Fwd:
        // If we want multiple languages, per https://stackoverflow.com/questions/16395814/
        // @"^([\[\(] *)?(RE?S?|FYI|RIF|I|FS|VB|RV|ENC|ODP|PD|YNT|ILT|SV|VS|VL|AW|WG|ΑΠ|ΣΧΕΤ|ΠΡΘ|תגובה|הועבר|主题|转发|FWD?) *([-:;)\]][ :;\])-]*|$)|\]+ *$", RegexOptions.IgnoreCase
        Regex regex = new Regex(@"^(?>(?:re|fwd|fw) *: *)*", RegexOptions.IgnoreCase);
        string strippedSubject = regex.Replace(subject, string.Empty);

        // Among open tickets, if we find more than one ticket with this Title, we grab the last one.
        List<Ticket> tickets = db.Tickets.Where(a => OpenIDs.Contains(a.Status_ID) && a.Title.Replace("re:", "") == strippedSubject).OrderByDescending(a => a.LastQueueDate).ToList();
        if (tickets.Count() >= 1)
        {
            ticket = tickets.First();
        }
    }
    // else we don't know the email address, so just fall through and return null

    return ticket;
 }

Итак, прямо сейчас, если в заголовке заявки в поле VARCHAR базы данных SQL есть RE:, я не нахожу совпадения. Примеры заголовков заявок, которые включают RE: и FW:, копируются и вставляются вручную из строк темы электронной почты, поэтому я не собираюсь удалять их до того, как они будут зафиксированы в базе данных.

После публикации этого, когда я выходил за дверь, мне пришло в голову, что как только я отфильтрую билеты по клиенту, у меня уже будет список в памяти. Итак, я должен иметь возможность дешево использовать регулярное выражение. Предполагая, что EF позволит мне это сделать.

Я рад услышать любые другие идеи.

Если вы ищете конкретную строку — «название билета» — то почему бы просто не искать по заголовкам и игнорировать все остальное? Вы можете использовать параметр табличного значения (если ваша версия EF поддерживает это)

stuartd 12.04.2023 16:54

Я не понимаю, где у тебя электронная почта? или вы работаете со списком строк?

Leandro Bardelli 12.04.2023 18:02

Вам нужно поделиться с нами своим классом сущностей, какое хранилище данных вы используете, какой тип LINQ у вас уже есть... очень сложно сказать, что вы пытаетесь здесь сделать.

mlibby 12.04.2023 18:04

Если аргумент темы для FindExistingTicket не удаляется и тема в поле базы данных не удаляется, почему вы удаляете параметр темы только для того, чтобы применить ту же логику внутри вашего выражения/запроса LINQ? Почему бы просто не использовать необработанную тему в своем запросе? Затем, когда у вас есть соответствующий билет, удалите оскорбительные символы из ticket.Title в C#.

mlibby 12.04.2023 20:28

Почему бы просто не использовать s.EndsWith(original). В любом случае производительность будет не очень хорошей в любом случае. База данных не может использовать здесь индексы.

Svyatoslav Danyliv 13.04.2023 07:02

Причина, по которой я их удаляю, заключается в том, что во многих случаях они будут меняться. По мере роста цепочки электронной почты некоторые почтовые программы будут видеть «re:», а затем добавят «RE:», и теперь у нас есть «RE: re:». И так далее. Множество способов, которыми они могут быть добавлены в строку темы. Другой способ сказать это: я не могу гарантировать, что они останутся последовательными. И если я сдираю их с одной стороны, мне придется сдирать их с другой. У меня нет хорошего способа выяснить, что оставить позади.

Mighty 13.04.2023 15:29

Я протестировал его с помощью EndsWith, и он работал в моих простых тестах. Но я могу представить ситуации, когда в названии билета есть RE:. Возможно, не часто, но я вижу, что это происходит. Таким образом, у субъекта будет удален этот внутренний RE:, и EndsWith больше не будет совпадать.

Mighty 13.04.2023 17:13
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
7
69
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

// Check to see if we know this email address
Contact contact = db.Contacts.Where(a => a.ContactStatu.Status.Equals("Active") && a.email.ToLower().Contains(from)).FirstOrDefault();
if (contact != null)
{
    // Grab a list of only this client's open tickets.
    List<Ticket> clientTickets = db.Tickets.Where(a => OpenIDs.Contains(a.Status_ID) && a.Company_ID == contact.customer_id).OrderByDescending(a => a.LastQueueDate).ToList(); // sort descending strip

    // Search for a ticket where the Subject matches the Title.
    // First, strip off any re: or Fwd:
    // If we want multiple languages, per https://stackoverflow.com/questions/16395814/
    // @"^([\[\(] *)?(RE?S?|FYI|RIF|I|FS|VB|RV|ENC|ODP|PD|YNT|ILT|SV|VS|VL|AW|WG|ΑΠ|ΣΧΕΤ|ΠΡΘ|תגובה|הועבר|主题|转发|FWD?) *([-:;)\]][ :;\])-]*|$)|\]+ *$", RegexOptions.IgnoreCase
    Regex regex = new Regex(@"^(?>(?:re|fwd|fw) *: *)*", RegexOptions.IgnoreCase);
    string strippedSubject = regex.Replace(subject, string.Empty);

    // If we find more than one ticket with this Title, we grab the last one.
    List<Ticket> tickets = clientTickets.Where(a => regex.Replace(a.Title, string.Empty)
        == strippedSubject).OrderByDescending(a => a.LastQueueDate).ToList();
    if (tickets.Count() >= 1)
    {
        ticket = tickets.First();
    }
}
// else we don't know the email address, so just fall through and return null

Спасибо, что помогли мне обдумать это

Другие вопросы по теме