#c# #kdb
#c# #kdb
Вопрос:
Я использую C # для выполнения q-кода в базе данных KDB с использованием c.cs
библиотеки, предоставляемой KX. Я предоставляю аргументы в виде объектов (целых чисел, строк, экземпляров Dict и т. Д.) c.k
методу в этой библиотеке, И все это работает нормально. Однако, когда у меня есть запрос, который не работает с использованием этого метода, я неизменно хочу сделать, это взять запрос, который я только что выполнил через адаптер C #, и повторно выполнить его в консоли Q, чтобы я мог поработать с ним и выяснить, что я сделал неправильно. Проблема в том, что в среде C # то, что у меня есть в качестве аргументов для моей функции Q (в некоторых случаях несколько сложные деревья аргументов на основе словаря), очень сложно вручную преобразовать мои аргументы в func[arg1;arg2;arg3...];
формат, ожидаемый консолью Q. Что я действительно хотел бы иметь возможность сделать, так это передать мои аргументы функции, которая перекомпонировала бы исходный запрос в синтаксисе, который позволил бы мне легко повторно выполнить исходный запрос в консоли. Что-то вроде этого:
В C#
var client = new c();
[connect]
var funcName = "myFunc";
var arg1 = "test";
var arg2 = 12345;
var arg3 = new c.Dict(new [] { "a", "b" }, new [] { true, false });
try {
var result = c.k(funcName, arg1, arg2, arg3);
} catch {
var composedStatement = c.k("getComposedStatement", funcName, new[] { arg1, arg2, arg3 });
// composedStatement: "myFunc[`test;12345i;`a`b!10b];"
Logger.LogError("KDB Query failed: " composedStatement);
}
В Q
getComposedStatement:{[funcName;arguments]
:(string funcName),"[",(qWizardryGoesHere arguments),"];";
}
Надеюсь, это понятно, чего я пытаюсь достичь. Важно то, что getComposedStatement
функция принимает имя функции и произвольное количество аргументов, которые могут быть любого типа, включая вложенные типы (списки списков, список словарей, словарь разных типов и т.д.) И возвращает инструкцию, которую можно напрямую скопировать и вставить в консоль Q длявыполнение.
Комментарии:
1. Попробуйте следующее: var result = c.k(funcName, новый объект[] {arg1, arg2, arg3});
2. Прошу прощения, я думаю, вы, возможно, пропустили суть моего вопроса. var result = c.k(funcName, arg1, arg2, arg3); работает нормально (я также иногда делаю это так, как вы предлагали). То, что я ищу, — это универсальный способ перекомпонирования исполняемого оператора Q из аргументов объекта, чтобы, если в myFunc есть ошибка, я мог протестировать ее с помощью аргументов, чтобы выяснить, почему. Я ищу помощи в части Q, в частности, там, где я сказал «qWizardryGoesHere» 🙂
Ответ №1:
Я думаю, это то, что вы ищете в функции kdb.
Используется .Q.s1
для получения строкового представления для каждого параметра, а затем sv
для получения ;
отдельной строки для параметров. Также есть несколько дополнительных битов для создания .
/ @
apply:
getComposedStatement:{
// conditional to create a . or @ apply depending on number of parameters
// @ apply will only work with 1 parameter
$[1 < count y;".";"@"],
"[`",x,";(",(";" sv .Q.s1 each y),")]"
}
Полезные ссылки:
https://code.kx.com/q/ref/dotq/#qs1-string-representation
https://code.kx.com/q/ref/apply/
Редактировать: лучшим подходом, который поможет вам отлаживать в q, было бы полностью отказаться от решения на основе строк и создать отладочную переменную. Тогда у вас могли бы быть функции и параметры, уже доступные в консоли q, которые можно запускать с eval .debug
createDebug:{
// simply create a list with function name and parameters
// assign it to the .debug namespace so it is available
// outside of the function call.
.debug:(,/)enlist each x,y;
}
testFunc:{1 2 3!(x;y;z)}
createDebug[`testFunc;("test";12345i;`a`b!10b)]
show .debug
(`testFunc;"test";12345;(`a`b)!10b)
eval .debug
key value
1 "test"
2 12345
3 (`a`b)!10b
Редактировать 2:
Поскольку у OP возникают проблемы с объектами размером более 2000 символов, другим способом сделать это было бы использовать JSON. Я не уверен, как это будет обрабатываться в C #, но попробовать стоит.
getComposedStatement:{
(x;.j.j each y)
}
// 3rd arg is a very large dictionary
getComposedStatement[`testFunc;("test";12345i;(til 2000)!2000?`3)]
(`testFunc;(""test"";"12345";{"0":"gia","1":"dmj","2":"pnh","3":"ofc","4":"hon","5":"jjb", ...
Затем вам придется использовать функцию run на другой стороне, чтобы преобразовать json обратно:
runComposedStatement:{
eval (first x),.j.k each last x
}
runComposedStatement[getComposedStatement[`testFunc;("test";12345i;(til 2000)!2000?`3)]]
(1j, 2j, 3j)!("test";12345f;(`0`1`2`3`4`5`6`7`8`9`10`11`12`13`14`15 ...
Я не хочу публиковать весь словарь, но я проверил, что он был полным. Надеюсь, это может достичь того, чего вы хотите, или хотя бы на один шаг ближе. Может потребоваться больше для обработки JSON.
Комментарии:
1. Отлично — это именно то, что мне было нужно, большое спасибо! На самом деле есть только одна проблема — .Q.s1, похоже, жестко запрограммирован, чтобы ограничить его вывод до 1999 символов — вы можете подумать, что этого будет достаточно для меня, но вы ошибаетесь. Есть идеи, как увеличить этот предел?
2. Интересно. Я не уверен, что это ограничение .Q.s1, но мне придется изучить его. Тем не менее, я думаю, что другой подход позволит получить желаемую отладку, в которой вы нуждаетесь. См. Редактирование выше
3. Спасибо, Мэтт. Я действительно рассматривал этот подход и сделаю это таким образом, если необходимо — я предпочитаю подход .Q.s1, хотя контекст, в котором я его использую, — это несколько производственных приложений, множество разных запросов, разные серверы и попытки фиксировать неудачные запросы в журналах для последующего просмотра. Сохранение параметров в памяти на сервере отлично подходит для отладки, но я продолжаю сталкиваться с производственными проблемами, вызванными неожиданными вводами пользовательских данных, и хранение аргументов в памяти будет потеряно при перезапуске Q процессов.
4. Что касается проблемы .Q.s1, вы можете воспроизвести ее с помощью инструкции «count .Q.s1 `long_string_with_2000_or_more_chars» — результатом всегда будет 1999, а представленная строка будет заканчиваться на «..» — это довольно досадное ограничение на то, что в противном случае было бы идеальным решением моей проблемы.
5. Я думаю, значение ограничения в 2000 символов заключается в том, что это максимальный размер, до которого вы можете развернуть консоль. После каждого перезапуска я обычно запускаю c 10000 10000, чтобы увеличить размер консоли, но когда я затем запускаю c, он сообщает размер консоли как 2000 2000i , что, очевидно, является пределом. .Q.s1, очевидно, должен использовать настроенный размер консоли для ограничения вывода