Zapytanie IQL często działają bardzo w skryptach Groovy’ego
Ostatnio bardzo mnie zdziwił fakt, że zapytania IQL zawierające funkcje outboundReferences() działają stosunkowo szybko w wyszukiwarce obiektów, ale są ekstremalnie wolne w skryptach Groovy’ego. Niejednokrotnie potrzebowałem pobrać obiekty Insight (Assets) i użyć ich w post funkcjach, REST Endpoitnach itp., ale nie mogłem sobie pozwolić na tak długie czasy odpowiedzi.
Warunki początkowe
- Utworzona lista obiektów Insight (Assets) jako List<ObjectBean> pod zmienną objectsForLoop.
- Utworzona lista wszystkich obiektów Insight (Assets), które mogą być użyte jako inbound references. Wszystkie z nich są dziećmi typu obiektu „sample”.
- Każdy element z listy objectsForLoop zawiera zero, jedną lub wiele relacji inbound references do innych obiektów Insight (Assets).
- W wyniku działania skryptu ma zostać wyświetlona lista wszystkich obiektów z listy objectsForLoop z powiązaniami inbound references.
HAVING outboundReferences()
Najprostszym sposobem wyświetlenia wszystkich obiektów Insight (Assets) i ich powiązań inbound references wydaje się być zapytanie IQL. Listę wyników moża uzyskać w trakcie iteracji obiektu objectsForLoop. W rozważanym scenariuszu jest ok. 10000 obiektów Insight (Assets) i 60 możliwych powiązań inbound references. W poniższym przypadku wykonanie skryptu zajęło więcej niż 3 minuty!
import com.atlassian.jira.component.ComponentAccessor;
// get the Insight class
Class iqlFacadeClass = ComponentAccessor.getPluginAccessor().getClassLoader().findClass("com.riadalabs.jira.plugins.insight.channel.external.api.facade.IQLFacade");
def iqlFacade = ComponentAccessor.getOSGiComponentInstanceOfType(iqlFacadeClass);
// get the 'objectsForLoop' list
def objectsForLoop = iqlFacade.findObjectsByIQLAndSchema(<schema_id>, <IQL query>);
objectsForLoop.each() {
object ->
// find all references wich exist as outboundReferences in the current object
def references = iqlFacade.findObjectsByIQLAndSchema(<schema_id>, "objectTypeId IN objectTypeAndChildren(\"sample\") AND object HAVING outboundReferences(Key = object.getKey()");
// some code.....
// references => objects where the current object exists as outbound reference
// object => current object from iteration
}
Moje rozwiązanie
Powiązania inbound i outbound references są zagnieżdzone bardzo głęboko w sktrukturze obiektów. Na początku należy pobrać ObjectAttributeBeans z obiektu Insight (Assets), a następnie ObjectAttributeValueBeans. Identyfikatory referencji są przechowywane jako wartości w ObjectAttributeValueBeans values. Wygląda to nieco skomplikowanie, ale chciałem sprawdzić jak to rozwiązanie zadziała. Byłem mocno zaskoczyny, ponieważ wykonanie skryptu zajęło zaledwie 1.7 sekundy.
import com.atlassian.jira.component.ComponentAccessor
// get the Insight class
Class iqlFacadeClass = ComponentAccessor.getPluginAccessor().getClassLoader().findClass("com.riadalabs.jira.plugins.insight.channel.external.api.facade.IQLFacade");
def iqlFacade = ComponentAccessor.getOSGiComponentInstanceOfType(iqlFacadeClass);
// get the 'objectsForLoop' list
def objectsForLoop = iqlFacade.findObjectsByIQLAndSchema(<schema_id>, <IQL query>);
objectsForLoop.each() {
object ->
// find all possible outboundReferneces
def references = iqlFacade.findObjectsByIQLAndSchema(<schema_id>, "objectTypeId IN objectTypeAndChildren(\"sample\")");
List referencesFromObject = new ArrayList<>();
references.each(){
reference ->
reference.getObjectAttributeBeans().each() {
referenceObjectAttributeBean ->
referenceObjectAttributeBean.getObjectAttributeValueBeans().each() {
if (referenceObjectAttributeValueBean.getValue()==object.getId())
referencesToAdd.add(reference);
}
}
}
references = referencesFromObject;
// some code.....
// references => objects where the current object exists as outbound reference
// object => current object from iteration
};