Jak optymalizować zapytania IQL „HAVING outboundReferences()” w skryptach Groovy’ego (Jira, Insight)

Jira Server / Data Center

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

  1. Utworzona lista obiektów Insight (Assets) jako List<ObjectBean> pod zmienną objectsForLoop.
  2. 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”.
  3. Każdy element z listy objectsForLoop zawiera zero, jedną lub wiele relacji inbound references do innych obiektów Insight (Assets).
  4. 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!

Groovy
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.

Groovy
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
};
Go to top