barbitoff programmer`s blog

Здесь я публикую заметки из программерской жизни: грабли, на которые мне случилось наступить, проблемы, для которых было найдено элегантное (или не очень) решение, а также все, с чем мне пришлось столкнуться и чем хотелось бы поделиться =)
PS Если хотите меня поблагодарить - на странице есть 3 места, чтобы это сделать =)

четверг, 20 октября 2016 г.

OQL: запись данных из хип-дампа в файл

Бывают ситуации, когда средств OQL недостаточно для проведения требующегося анализа хип-дампа, и проще выгрузить нужные данные в файл и проанализировать их внешним инструментом. 
К примеру, столкнулся со следующей задачей: есть некий класс со строковым полем. В хип-дампе около 10 миллионов объектов данного класса, и нужно по ним собрать статистику, какое значение данного строкового поля встречается сколько раз. В OQL нет аналога SQL-ного GROUP BY, поэтому, поломав голову над реализацией группировки с применением комбинаций map / sort / filter и упершись в то, что полученное решение работает крайне медленно, я решил выгрузить все строки в файл, и потом уже обработать этот файл каким-нибудь более удобным, чем OQL, инструментом.
Например, следующий код выведет в файл namespaces.log пространства имен родительских элементов всех объектов класса OMTextImpl:
var file = new java.io.FileWriter("T:/namespaces.log");
unique(map(
  heap.objects('org.apache.axiom.om.impl.llom.OMTextImpl'),
  function(v) {
    var ns = v.parent == null ? "null_parent" :(v.parent.ns == null ? "null_ns" : (v.parent.ns.uri == null ? "null_uri" : v.parent.ns.uri));
    file.write(new java.lang.String(ns.toString() + "\r\n"));
    file.flush();
    return "1";
  }
));
А такой код - локальные имена всех объектов OMElementImpl:
var file = new java.io.FileWriter("T:/omelements.log");
unique(map(
  heap.objects('org.apache.axiom.om.impl.llom.OMElementImpl'),
  function(v) {
    file.write(new java.lang.String(v.localName));
    file.write(new java.lang.String("\r\n"));
    file.flush();
    return "1";
  }
)); 
Зачем нужен unique и return "1": дело в том, что, по крайней мере, Netbeans считает, что если OQL вернул 100 объектов, нужно прекратить итерацию, вывести эти 100 объектов пользователю и написать, что, де, "слишком много результатов, уточните запрос".  Т.е. если из запросов выше убрать unique, в файл будут записаны значения только из первых 100 найденных объектов заданного класса. Использование же unique заставит OQL-движок продолжать итерации, пока не будет найдено 100 уникальных значений, а т.к. map-функция всегда возвращает константу "1", это эквивалентно итерации по абсолютно всем объектам.
PS Хорошая справка по OQL: http://visualvm.java.net/oqlhelp.html

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