9:01, EEST
July 6, 2015
Hi,
I have a question regarding performance improvements. I have to read and persist all node values of the root node of a machine.
Currently I iterate over all nodes recursively using the ‘browse’ method of AddressSpace. I takes about 6 Minutes. Is there maybe a more efficient way how I can retrieve
all child node values?
Thanks in advance.
10:20, EEST
April 3, 2012
Hi,
Can you post some code; it would make it much easier to analyze. What do you mean by a “machine”, a complete UA server? or some UA types/instances under a FolderType node?. In case you do try browse from the Root node of the server (Identifiers.RootFolder), there is not much that can be helped since UA address space is not designed to be browsed completely. You can do it of course, but since there are lots of nodes (i.e. types, and lots of properties in nodes anyway) it will take long. Any possiblity that you could explain why you need to do it?
In case you were happen to be building a graphical view of the address space of the server, i.e. similar to which UaExpert has; those are usually done so that whenever user expands the node in the view, the browse is done then, not by trying to cache the whole tree beforehand.
Also, as long as you use the ReferenceDescriptions returned by the AddressSpace.browse it is somewhat best you can do. IF you do call AddressSpace.getNode, then the node is cached as UaNode implementation, i.e. it does fetch the attributes, references and Properties of that node. This can take time if done for a large amount of nodes. Also the cache has limited size and duration, defaults are 5000 nodes and 1 second. If your code tries to do something with more than 5000 nodes at the same time or longer than 1 second, it might trigger fetching the data again when you call AddressSpace.getNode with the same NodeId. For example our graphical client https://prosysopc.com/products/opc-ua-client/ only uses the getNode for the selected node in the address space view and not for every node seen in the view.
– Bjarne
11:48, EEST
July 6, 2015
Hi Bjarne,
yes, with ‘machine’ I meant the UA server running on a injection moulding machine. I browse not from the main root node (Identifiers.RootFolder) but 2 hierarchy levels deeper. For example: Root->Objects->Arburg. I have to log the complete data of this node (and all its children) for each single peace that is produced on the machine. This is done for optimizing and analyzing the production process. Under this node there are about 22 000 child nodes in sum. Here is my code:
public ArburgHistory getHistoryForNode(ArburgNode node) {
//get arburg node
UaNode startNode = addressSpace.getNode(new NodeId(2, 1111);
…
}
//get nodes recursive
private List<ArburgHistoryEntry> browseTree(AddressSpace addressSpace, UaNode node, ArburgHistory history) {
List<ArburgHistoryEntry> historyList = new ArrayList<ArburgHistoryEntry>();
try {
List<ReferenceDescription> browseList = addressSpace.browse(node.getNodeId());
Iterator<ReferenceDescription> browseListIt = browseList.iterator();
List<ArburgHistoryEntry> historyTmp = new ArrayList<ArburgHistoryEntry>();
while (browseListIt.hasNext()) {
ReferenceDescription refDescr = (ReferenceDescription) browseListIt.next();
historyTmp.addAll(browseTree(addressSpace, addressSpace.getNode(refDescr.getNodeId()), history));
}
ArburgHistoryEntry historyEntry = getHistoryEntry(node); //map UaNode to entity objetct
historyEntry.setArburgHistory(history);
for (ArburgHistoryEntry arburgHistoryEntry : historyTmp) {
if (arburgHistoryEntry.getParentHistoryEntry() == null) {
arburgHistoryEntry.setParentHistoryEntry(historyEntry);
historyEntry.setArburgHistory(history);
}
historyList.add(arburgHistoryEntry);
}
historyList.add(historyEntry);
} catch (ServiceException | StatusException | AddressSpaceException e) {
String msg = MessageFormat.format("Browse list empty or not readable at node: ”{0}”", node.getBrowseName());
log.error(msg, e);
}
return historyList;
}
13:55, EEST
April 3, 2012
Ok, seems to be interesting use case. I see 2 options.
1)
You could just use the ReferenceDescriptions without fetching the node with getNode and use UaClient.read methods to read the Attributes you need. ReferenceDescription contains the NodeId/BrowseName/DisplayName/NodeClass attributes + type definition. In UA you can use the Read service for multiple attributes for multiple nodes in one call so it should be more efficient. For attributes other than value, you might need to do the ReadValueId for the calls in UaClient, use null for IndexRange and DataEncoding. Also for this large amount, you might want to limit the the number of items you read in the same request (maybe try with reading attributes for one node at a time and see if it is fast enough). The server might set operation limits in Server/ServerCapabilities/OperationLimits but it is optional (as is the node too), if they are defined the UaClient will split the read, but it may also be that server has set no limits (or is not able to take 22000 x number of attributes you need reads in one request).
2)
Or you could just get the top level node with .getNode, and use UaNode.getReferences(Identifiers.HierarchicalReferences, false) to go forward and not use browse. Note that I have not used this method to traverse the entire address space (or a huge part of it anyway), so I would recommened the first option. You could also try to set the cache larger and more permanent, AddressSpace.getCache and .setMaxQueueLength and setNodeMaxAgeInMillis. You could also clear that after saving with .clear.
If you do both browse and .getNode for each node, it is essentially the same work done twice, since .getNode reads all references/attributes and property nodes when you call .getNode. The references are stored in a way that when you do call UaReference.getTargetNode it fetches it from the AddressSpace with .getNode automatically.
– Bjarne
(There is a third option which might be useful in cases like this in the future. The specification defines a service Query, which might help to do data searches like this (for instances of types). But to my knowledge there is not a server yet which would support this.)
7:08, EEST
July 6, 2015
11:11, EEST
April 3, 2012
Most Users Ever Online: 1919
Currently Online:
66 Guest(s)
Currently Browsing this Page:
1 Guest(s)
Top Posters:
Heikki Tahvanainen: 402
hbrackel: 144
rocket science: 88
pramanj: 86
Francesco Zambon: 83
Ibrahim: 78
Sabari: 62
kapsl: 57
gjevremovic: 49
Xavier: 43
Member Stats:
Guest Posters: 0
Members: 737
Moderators: 7
Admins: 1
Forum Stats:
Groups: 3
Forums: 15
Topics: 1524
Posts: 6450
Newest Members:
fannielima, kristiewinkle8, rust, christamcdowall, redaahern07571, nigelbdhmp, travistimmons, AnnelCib, dalenegettinger, howardkennerleyModerators: Jouni Aro: 1026, Pyry: 1, Petri: 0, Bjarne Boström: 1026, Jimmy Ni: 26, Matti Siponen: 346, Lusetti: 0
Administrators: admin: 1