LIMA
Libre Multilingual Analyzer — C++ API
Loading...
Searching...
No Matches
SpecificEntitiesXmlLogger.cpp
Go to the documentation of this file.
1// Copyright 2004-2020 CEA LIST
2// SPDX-FileCopyrightText: 2022 CEA LIST <gael.de-chalendar@cea.fr>
3//
4// SPDX-License-Identifier: MIT
5
8
18
19#include <fstream>
20#include <queue>
21
22using namespace std;
23using namespace Lima::Common::AnnotationGraphs;
25//using namespace boost;
26
27namespace Lima
28{
29namespace LinguisticProcessing
30{
31namespace SpecificEntities
32{
33
35
38 m_compactFormat(false),
39 m_language(0),
40 m_graph("PosGraph"),
41 m_followGraph(false)
42{
44 LDEBUG << "SpecificEntitiesXmlLogger::SpecificEntitiesXmlLogger()";
45}
46
47
50 Manager* manager)
51
52{
54 LDEBUG << "SpecificEntitiesXmlLogger::init";
55 AbstractTextualAnalysisDumper::init(unitConfiguration, manager);
56
57 m_language = manager->getInitializationParameters().media;
58
59 try
60 {
61 m_graph = unitConfiguration.getParamsValueAtKey("graph");
62 }
64 {
66 LWARN << "No 'graph' parameter in unit configuration '"
67 << unitConfiguration.getName() << "' ; using PosGraph";
68 m_graph = string("PosGraph");
69 }
70 try
71 {
72 std::string val = unitConfiguration.getParamsValueAtKey("compactFormat");
73 if (val == "yes" || val == "true" || val == "1")
74 {
75 m_compactFormat = true;
76 }
77 }
78 catch (Common::XMLConfigurationFiles::NoSuchParam& ) {} // do nothing: optional
79
80 try
81 {
82 auto str = unitConfiguration.getParamsValueAtKey("followGraph");
83 m_followGraph = (str == "1" || str == "true" || str == "yes");
84 }
85 catch (Common::XMLConfigurationFiles::NoSuchParam& ) {} // keep default value
86}
87
89 AnalysisContent& analysis) const
90{
92 LDEBUG << "SpecificEntitiesXmlLogger::process";
94
95 auto annotationData = std::dynamic_pointer_cast< AnnotationData >(analysis.getData("AnnotationData"));
96 if (annotationData == nullptr)
97 {
99 LERROR << "no annotationData ! abort";
100 return MISSING_DATA;
101 }
102
103 auto graphp = std::dynamic_pointer_cast<LinguisticAnalysisStructure::AnalysisGraph>(analysis.getData(m_graph));
104 if (graphp == nullptr)
105 {
106 SELOGINIT;
107 LERROR << "no graph "<< m_graph <<" ! abort";
108 return MISSING_DATA;
109 }
110 const auto& graph = *graphp;
111 auto lingGraph = const_cast<LinguisticGraph*>(graph.getGraph());
112 auto tokenMap = get(vertex_token, *lingGraph);
113
114 auto metadata = std::dynamic_pointer_cast<LinguisticMetaData>(analysis.getData("LinguisticMetaData"));
115 if (metadata == nullptr)
116 {
117 SELOGINIT;
118 LERROR << "no LinguisticMetaData ! abort";
119 return MISSING_DATA;
120 }
121
122 auto dstream = initialize(analysis);
123 auto& out = dstream->out();
124
125 uint64_t offset = 0;
126 try
127 {
128 offset = QString::fromStdString(metadata->getMetaData("StartOffset")).toUInt();
129 }
131 {
132 // do nothing: not set in analyzeText (only in analyzeXmlDocuments)
133 }
134
135 uint64_t offsetIndexingNode = 0;
136 try
137 {
138 offsetIndexingNode = QString::fromStdString(
139 metadata->getMetaData("StartOffsetIndexingNode")).toUInt();
140 }
142 {
143 // do nothing: not set in analyzeText (only in analyzeXmlDocuments)
144 }
145
146 std::string docId;
147 try
148 {
149 docId = metadata->getMetaData("DocId");
150 }
152 {
153 // do nothing: not set in analyzeText (only in analyzeXmlDocuments)
154 }
155
156 if (m_compactFormat)
157 {
158 out << "<entities docid=\"" << docId
159 << "\" offsetNode=\"" << offsetIndexingNode
160 << "\" offset=\"" << offset
161 << "\">" << std::endl;
162 }
163 else
164 {
165 out << "<specific_entities>" << std::endl;
166 }
167// SELOGINIT;
168
169 if (m_followGraph)
170 {
171 // instead of looking to all annotations, follow the graph (in
172 // morphological graph, some vertices are not related to main graph:
173 // idiomatic expressions parts and named entity parts)
174 // -> this will not include nested entities
175
176 auto tokenList = std::dynamic_pointer_cast<AnalysisGraph>(analysis.getData(m_graph));
177 if (tokenList == nullptr)
178 {
179 LERROR << "graph " << m_graph << " has not been produced: check pipeline";
180 return MISSING_DATA;
181 }
182 auto graph = tokenList->getGraph();
183 //const FsaStringsPool& sp=Common::MediaticData::MediaticData::single().stringsPool(m_language);
184
185 std::queue<LinguisticGraphVertex> toVisit;
186 std::set<LinguisticGraphVertex> visited;
187 toVisit.push(tokenList->firstVertex());
188
189 LinguisticGraphOutEdgeIt outItr, outItrEnd;
190 while (!toVisit.empty())
191 {
192 auto v = toVisit.front();
193 toVisit.pop();
194 if (v == tokenList->lastVertex())
195 {
196 continue;
197 }
198
199 for (boost::tie(outItr, outItrEnd) = out_edges(v, *graph);
200 outItr != outItrEnd; outItr++)
201 {
202 auto next = target(*outItr, *graph);
203 if (visited.find(next) == visited.end())
204 {
205 visited.insert(next);
206 toVisit.push(next);
207 }
208 }
209 const auto annot = getSpecificEntityAnnotation(v, annotationData.get());
210 if (annot != 0)
211 {
212 outputEntity(annotationData.get(), out, v, annot, tokenMap, offset);
213 }
214 }
215 }
216 else
217 {
218 // take all annotations
219 AnnotationGraphVertexIt itv, itv_end;
220 boost::tie(itv, itv_end) = vertices(annotationData->getGraph());
221 for (; itv != itv_end; itv++)
222 {
223 // LDEBUG << "SpecificEntitiesXmlLogger on annotation vertex " << *itv;
224 if (annotationData->hasAnnotation(*itv, QString::fromUtf8("SpecificEntity")))
225 {
226 // LDEBUG << " it has SpecificEntityAnnotation";
227 const SpecificEntityAnnotation* annot = nullptr;
228 try
229 {
230 annot = annotationData->annotation(
231 *itv, QString::fromUtf8("SpecificEntity")).pointerValue<SpecificEntityAnnotation>();
232 }
233 catch (const boost::bad_any_cast& )
234 {
235 SELOGINIT;
236 LERROR << "This annotation is not a SpecificEntity; SE not logged";
237 continue;
238 }
239
240 // recuperer l'id du vertex morph cree
242 if (!annotationData->hasIntAnnotation(*itv,
243 QString::fromStdString(m_graph)))
244 {
245 // SELOGINIT;
246 // LDEBUG << *itv << " has no " << m_graph << " annotation. Skeeping it.";
247 continue;
248 }
249 v = annotationData->intAnnotation(*itv, QString::fromStdString(m_graph));
250 outputEntity(annotationData.get(), out, v, annot, tokenMap, offset);
251 }
252 }
253 }
254
255 // LDEBUG << " all vertices done";
256 if (m_compactFormat)
257 {
258 out << "</entities>" << std::endl;
259 }
260 else
261 {
262 out << "</specific_entities>" << std::endl;
263 }
264
265 TimeUtils::logElapsedTime("SpecificEntitiesXmlLogger");
266 return SUCCESS_ID;
267}
268
269void SpecificEntitiesXmlLogger::outputEntity(AnnotationData* annotationData,
270 std::ostream& out,
272 const SpecificEntityAnnotation* annot,
273 const VertexTokenPropertyMap& tokenMap,
274 uint64_t offset) const
275{
276 auto vToken = tokenMap[v];
277 // LDEBUG << "SpecificEntitiesXmlLogger tokenMap[" << v << "] = " << vToken;
278 if (vToken == nullptr)
279 {
280 SELOGINIT;
281 LERROR << "SpecificEntitiesXmlLogger::outputEntity: Vertex " << v
282 << " has no entry in the analysis graph token map. This should not happen !!";
283 }
284 else
285 {
286 if (m_compactFormat)
287 {
288 // same format as RecognizerResultLogger
289 // Check compatibility with RecognizerResultLogger
290 // display list of components and normalization
291 // components are the list of features whose value are strings in the texte with a (position,length) info
292 // normalisations are the list of features whose value are computed and does not have (position,length) info
293 const auto& features = annot->getFeatures();
294 out << "<entity>"
295 //<< "<pos>" << offset+annot->getPosition() << "</pos>"
296 << "<pos>" << offset+annot->getPosition() << "</pos>"
297 << "<len>" << annot->getLength() << "</len>"
298 //<< "<typeNum>" << (*m).getType() << "</typeNum>"
299 << "<type>"
301 << "</type>"
302 << "<string>"<< Common::Misc::transcodeToXmlEntities(vToken->stringForm()).toStdString() << "</string>"
303 << "<components>";
304 for (auto featureItr = features.cbegin(), features_end = features.cend();
305 featureItr != features_end; featureItr++)
306 {
307 if( featureItr->getPosition() != UNDEFPOSITION )
308 {
309 out << "<" << featureItr->getName();
310 out << " pos=\"" << featureItr->getPosition() << "\"";
311 out << " len=\"" << featureItr->getLength() << "\"";
312 out << ">";
314 QString::fromStdString(
315 featureItr->getValueString())
316 ).toStdString()
317 << "</" << featureItr->getName() << ">";
318 }
319 }
320
321 // TODO: Follow "belongstose" links to outputs embeded entities as components
322 // Get the current annotationVertex (is there any more simple solution???)
323 auto matches = annotationData->matches(m_graph,v,"annot");
325
326 auto it = matches.begin();
327 for(; it != matches.end(); it++)
328 {
329 va1 = *it;
330 SELOGINIT;
331 LDEBUG << "SpecificEntitiesXmlLogger::outputEntity: get agv = " << va1;
332 if (annotationData->hasAnnotation(
333 va1, QString::fromStdString("SpecificEntity")))
334 break;
335 }
336 if( it == matches.end() )
337 {
338 SELOGINIT;
339 LERROR << "SpecificEntitiesXmlLogger::outputEntity: could not find annotation of node "
340 << v << "in LinguisticGraph";
341 }
342 else
343 {
344 SELOGINIT;
345 LDEBUG << "SpecificEntitiesXmlLogger::outputEntity: agv " << va1
346 << " is a SpecificEntity Annotation";
347 // Follow "belongstose" out_edges to get annotationVertex of embededed NE
348 AnnotationGraphOutEdgeIt it1, it1_end;
349 boost::tie(it1, it1_end) = boost::out_edges(va1, annotationData->getGraph());
350 for (; it1 != it1_end; it1++)
351 {
352 if ( annotationData->intAnnotation((*it1), QString::fromUtf8("holds"))==1)
353 {
354 AnnotationGraphVertex va2 = target(*it1, annotationData->getGraph());
355 LDEBUG << "SpecificEntitiesXmlLogger::outputEntity: embeded agv = "
356 << va2;
357 // récupérer le noeud du graphe linguistique
358 auto v2 = annotationData->intAnnotation(
359 va2, QString::fromStdString(m_graph));
360 LDEBUG << "SpecificEntitiesXmlLogger::outputEntity: vertex in "
361 << m_graph << " is " << v2;
362 // récupérer l'annotation SpecifiEntity
363 if (annotationData->hasAnnotation(
364 va2, QString::fromUtf8("SpecificEntity")))
365 {
366 auto annot2 = annotationData->annotation(
367 va2, QString::fromUtf8("SpecificEntity")
368 ).pointerValue<SpecificEntityAnnotation>();
369 LDEBUG << "SpecificEntitiesXmlLogger::outputEntity: annot2 = " << annot2;
370 outputEntity(annotationData,out, v2, annot2, tokenMap, offset);
371 break;
372 }
373 }
374 }
375 }
376 out << "</components>"
377 << "<normalization>";
378 SELOGINIT;
379 LDEBUG << "SpecificEntitiesXmlLogger::outputEntity: features:" << features;
380 for (auto featureItr = features.begin(), features_end=features.end();
381 featureItr != features_end; featureItr++)
382 {
383 if( featureItr->getPosition() == UNDEFPOSITION )
384 {
385 out << "<" << featureItr->getName() << ">";
387 QString::fromStdString(featureItr->getValueString())).toStdString();
388 out << "</" << featureItr->getName() << ">";
389 }
390 }
391 out << "</normalization>"
392 << "</entity>" << std::endl;
393 }
394 else
395 {
396 // recuperer le vertex morph en question dans le graphe morph
397 // recuperer la chaine, la position et la longueur pour ce vertex morph
398 out << "<specific_entity>" << std::endl;
399 out << " <string>"
400 << Common::Misc::transcodeToXmlEntities(vToken->stringForm()).toStdString()
401 << "</string>" << std::endl;
402 out << " <position>" << vToken->position()<< "</position>" << endl;
403 out << " <length>" << vToken->length() << "</length>" << endl;
404 out << " <type>"
406 << "</type>" << std::endl;
407 out << " <normalization>" << std::endl;
408 const auto& features = annot->getFeatures();
409 SELOGINIT;
410 LDEBUG << "SpecificEntitiesXmlLogger::outputEntity: features:" << features;
411 for (auto featureItr = features.begin(), features_end = features.end();
412 featureItr != features_end; featureItr++)
413 {
414 if( featureItr->getPosition() == UNDEFPOSITION )
415 {
416 out << " <" << featureItr->getName() << ">";
418 QString::fromStdString(featureItr->getValueString())).toStdString();
419 out << "</" << featureItr->getName() << ">" << std::endl;
420 }
421 }
422 out << " </normalization>" << std::endl;
423 out << "</specific_entity>" << std::endl;
424 }
425 }
426}
427
428const SpecificEntityAnnotation* SpecificEntitiesXmlLogger::getSpecificEntityAnnotation(
430 const Common::AnnotationGraphs::AnnotationData* annotationData) const
431{
432 const SpecificEntityAnnotation* se = nullptr;
433
434 // check only entity found in current graph (not previous graph such as AnalysisGraph)
435
436 auto matches = annotationData->matches(m_graph,v,"annot");
437 for (auto it = matches.cbegin(); it != matches.cend(); it++)
438 {
439 auto vx = *it;
440 if (annotationData->hasAnnotation(vx, QString::fromUtf8("SpecificEntity")))
441 {
442 //BoWToken* se = createSpecificEntity(v,*it, annotationData, anagraph, posgraph, offsetBegin);
443 se = annotationData->annotation(
444 vx,
445 QString::fromUtf8("SpecificEntity")).pointerValue<SpecificEntityAnnotation>();
446 if (se != 0)
447 {
448 return se;
449 }
450 }
451 }
452 return se;
453
454}
455
456} // SpecificEntities
457} // LinguisticProcessing
458} // Lima
This file is the main header file for the data related to annotation graphs.
#define UNDEFPOSITION
#define LWARN
Definition LimaCommon.h:160
#define LDEBUG
Definition LimaCommon.h:157
#define LERROR
Definition LimaCommon.h:161
boost::property_map< LinguisticGraph, vertex_token_t >::type VertexTokenPropertyMap
@ vertex_token
LinguisticGraph::vertex_descriptor LinguisticGraphVertex
LinguisticGraph::out_edge_iterator LinguisticGraphOutEdgeIt
boost::adjacency_list< boost::vecS, boost::vecS, boost::bidirectionalS, LinguisticVertexProperties > LinguisticGraph
Property to identify the chains in the graph.
#define SELOGINIT
Defines a Factory to create Object of type Base.
#define SPECIFICENTITIESXMLLOGGER_CLASSID
Holds all data that pass through the ProcessUnits Analysis data are shared pointers,...
std::shared_ptr< AnalysisData > getData(const QString &id)
return AnalysisData by id
Holds an annotation graph and gives an API to manipulate it.
uint64_t intAnnotation(AnnotationGraphVertex v1, AnnotationGraphVertex v2, const LimaString &annot) const
std::set< AnnotationGraphVertex > matches(const std::string &first, AnnotationGraphVertex firstVx, const std::string &second) const
Gets the set of vertices matched in the second graph by the given vertex of the first graph.
const GenericAnnotation & annotation(AnnotationGraphVertex v1, AnnotationGraphVertex v2, const LimaString &annot) const
LimaString getEntityName(const EntityType &type) const
return a message when a 'param' was not found
Manage initialization of InitializableObjects using configuration module and parameters.
const InitializationParameters & getInitializationParameters() const
get Initialization Parameters
std::shared_ptr< DumperStream > initialize(AnalysisContent &analysis) const
virtual void init(Common::XMLConfigurationFiles::GroupConfigurationStructure &unitConfiguration, Manager *manager) override
initialize with parameters from configuration file.
virtual LimaStatusCode process(AnalysisContent &analysis) const override
Process on data in analysisContent.
virtual void init(Common::XMLConfigurationFiles::GroupConfigurationStructure &unitConfiguration, Manager *manager) override
initialize with parameters from configuration file.
A representation of a specific entity to store in the annotation graph.
static const MediaticData & single()
const singleton accessor
Definition Singleton.h:51
static void logElapsedTime(const std::string &mess, const std::string &taskCategory=std::string(""))
log the number of microseconds since last UpdateCurrentTime
static void updateCurrentTime(const std::string &taskCategory=std::string(""))
store current time for new elapsed time computation
AnnotationGraph::vertex_iterator AnnotationGraphVertexIt
AnnotationGraph::vertex_descriptor AnnotationGraphVertex
AnnotationGraph::out_edge_iterator AnnotationGraphOutEdgeIt
bool hasAnnotation(AnnotationGraphVertex v, const LimaString &annot) const
LimaString transcodeToXmlEntities(const LimaString &str)
SimpleFactory< MediaProcessUnit, SpecificEntitiesXmlLogger > specificEntitiesXmlLoggerFactory(SPECIFICENTITIESXMLLOGGER_CLASSID)
NAUTITIA.
LimaStatusCode
Definition LimaCommon.h:236
@ SUCCESS_ID
Definition LimaCommon.h:237
@ MISSING_DATA
Definition LimaCommon.h:243
STL namespace.