Вызов всех экспертов ANTLR!
У меня есть сборка .NET, размещенная на веб-сайте IIS, в которой используется ANTLR для обработки запросов на естественном языке в стиле поисковой системы. Например, если пользователь вводит:
сыр и крекеры, а не чипсы
Он строит следующее утверждение:
И (И («сыр», «крекеры»), НЕ («чипсы»))
Затем мы запускаем это утверждение в нашем хранилище контента и предоставляем некоторый контент пользователю. 99,9% времени все отлично работает. Тем не менее, время от времени что-то не работает с ANTLR и размещенным на IIS сайтом, который выполняет эту обработку, застревает в каком-то состоянии ошибки и выдает ошибки без остановки, пока мы не выполним перезапуск IISReset / AppPool. После перезагрузки ошибки немедленно прекращаются.
Я фиксирую трассировку стека этих ошибок, которые я включил (санировал, согласно политике компании) ниже:
System.Text.EncoderFallbackException: Unable to translate Unicode character \uDCAF at index 111 to specified code page.
at System.Text.EncoderExceptionFallbackBuffer.Fallback(Char charUnknown, Int32 index)
at System.Text.EncoderFallbackBuffer.InternalFallback(Char ch, Char*& chars)
at System.Text.UTF8Encoding.GetBytes(Char* chars, Int32 charCount, Byte* bytes, Int32 byteCount, EncoderNLS baseEncoder)
at System.Text.EncoderNLS.GetBytes(Char* chars, Int32 charCount, Byte* bytes, Int32 byteCount, Boolean flush)
at System.Text.EncoderNLS.GetBytes(Char[] chars, Int32 charIndex, Int32 charCount, Byte[] bytes, Int32 byteIndex, Boolean flush)
at System.IO.StreamWriter.Flush(Boolean flushStream, Boolean flushEncoder)
at System.IO.StreamWriter.Write(Char[] buffer, Int32 index, Int32 count)
at System.IO.TextWriter.WriteLine(String value)
at System.IO.TextWriter.SyncTextWriter.WriteLine(String value)
at Antlr.Runtime.BaseRecognizer.EmitErrorMessage(String msg)
at Service123.Parser.atomicExpression() in Parser.cs:line 927
at Service123.Parser.notExpression() in Parser.cs:line 657
at Service123.Parser.orExpression() in Parser.cs:line 516
at Service123.Parser.andnotExpression() in Parser.cs:line 416
at Service123.Parser.andExpression() in Parser.cs:line 234
at Service123.Parser.startExpression() in Parser.cs:line 167
at Service123.Processor.ProcessQuery(String queryString) in Processor.cs:line 34
at Service123.Search.ProcessQueryString(String query) in Search.cs:line 1017
Ниже приведена (снова обработанная, согласно политике компании) копия моего файла грамматики:
grammar Parser;
options { language = CSharp2; output = AST; }
tokens { IMPLICIT_AND; }
@lexer::namespace { Service123.Parser }
@parser::namespace { Service123.Parser }
L_PARENTHESIS : '(';
R_PARENTHESIS : ')';
AND : ('A'|'a')('N'|'n')('D'|'d');
OR : ('O'|'o')('R'|'r');
ANDNOT : ('A'|'a')('N'|'n')('D'|'d')('N'|'n')('O'|'o')('T'|'t');
NOT : ('N'|'n')('O'|'o')('T'|'t');
fragment LETTER : ('a'..'z'|'A'..'Z');
fragment NUMBER : ('0'..'9');
fragment SYMBOL_1 : ('+'|'-'|'_'|'|'|'~'|'&'|'`'|'='|'['|']'|'{'|'}');
fragment SYMBOL_2 : ('!'|'@'|'#'|'$'|'%'|'^'|'*'|','|'.'|'/'|':'|';'|'<'|'>'|'?'|'\''|'\\');
fragment SYMBOL_QUOTE : ('"');
fragment SPACE : (' '|'\n'|'\r'|'\t'|'\u000C');
WS : (SPACE) { $channel=HIDDEN; };
PHRASE : (SYMBOL_QUOTE)(LETTER|NUMBER|SYMBOL_1|SYMBOL_2)+((SPACE)+(LETTER|NUMBER|SYMBOL_1|SYMBOL_2)+)+(SYMBOL_QUOTE);
WORD : (LETTER|NUMBER|SYMBOL_1)+;
startExpression : andExpression;
andExpression : ( andnotExpression -> andnotExpression )
(AND? e = andnotExpression -> ^(IMPLICIT_AND $andExpression $e))*;
andnotExpression : orExpression (ANDNOT^ orExpression)*;
orExpression : notExpression (OR^ notExpression)*;
notExpression : (NOT^)? atomicExpression;
atomicExpression : PHRASE | WORD | L_PARENTHESIS! andExpression R_PARENTHESIS!;
Я также записываю строки запросов, которые сопровождают эти ошибки, и они кажутся общими, заурядными английскими поисковыми терминами.
Что касается ошибки, то рассматриваемая кодовая точка не всегда \ uDCAF, но согласована на протяжении всего цикла ошибок; это всегда одна и та же кодовая точка, пока мы не откажемся от службы, а затем, когда ошибка снова появляется после недели, когда все работает нормально, все по-другому.
Все кодовые точки, которые я смог записать, являются частью суррогатной пары и сами по себе не представляют действительные глифы.
Я - признанный новичок ANTLR и не знаю достаточно о его внутренней работе, чтобы диагностировать намного дальше, чем это. Мне почти кажется, что во время выполнения ANTLR есть один синглтон, который каким-то образом облажается и делает всю дальнейшую обработку бесполезной, пока мы не перезагрузим сборки. У меня нет никаких доказательств этого, однако.
Если вам нужны подробности или разъяснения, пожалуйста, не стесняйтесь спрашивать, потому что я в своем уме.