mirror of
https://github.com/datahub-project/datahub.git
synced 2025-07-05 08:07:04 +00:00
1437 lines
42 KiB
Markdown
1437 lines
42 KiB
Markdown
# Rest.li API
|
|
|
|
You can access basic documentation on the API endpoints by opening the `/restli/docs` endpoint in the browser.
|
|
|
|
```
|
|
python -c "import webbrowser; webbrowser.open('http://localhost:8080/restli/docs', new=2)"
|
|
```
|
|
|
|
\*Please note that because DataHub is in a period of rapid development, the APIs below are subject to change.
|
|
|
|
#### Sample API Calls
|
|
|
|
#### Ingesting Aspects
|
|
|
|
To ingest individual aspects into DataHub, you can use the following CURL:
|
|
|
|
```shell
|
|
curl --location --request POST 'http://localhost:8080/aspects?action=ingestProposal' \
|
|
--header 'X-RestLi-Protocol-Version: 2.0.0' \
|
|
--header 'Content-Type: application/json' \
|
|
--data-raw '{
|
|
"proposal" : {
|
|
"entityType": "dataset",
|
|
"entityUrn" : "urn:li:dataset:(urn:li:dataPlatform:hive,SampleHiveDataset,PROD)",
|
|
"changeType" : "UPSERT",
|
|
"aspectName" : "datasetUsageStatistics",
|
|
"aspect" : {
|
|
"value" : "{ \"timestampMillis\":1629840771000,\"uniqueUserCount\" : 10, \"totalSqlQueries\": 20, \"fieldCounts\": [ {\"fieldPath\": \"col1\", \"count\": 20}, {\"fieldPath\" : \"col2\", \"count\": 5} ]}",
|
|
"contentType": "application/json"
|
|
}
|
|
}
|
|
}'
|
|
```
|
|
|
|
Notice that you need to provide the target entity urn, the entity type, a change type (`UPSERT` + `DELETE` supported),
|
|
the aspect name, and a JSON-serialized aspect, which corresponds to the PDL schema defined for the aspect.
|
|
|
|
For more examples of serialized aspect payloads, see [bootstrap_mce.json](https://github.com/datahub-project/datahub/blob/master/metadata-ingestion/examples/mce_files/bootstrap_mce.json).
|
|
|
|
#### Ingesting Entities (Legacy)
|
|
|
|
> Note - we are deprecating support for ingesting Entities via Snapshots. Please see **Ingesting Aspects** above for the latest
|
|
> guidance around ingesting metadata into DataHub without defining or changing the legacy snapshot models. (e.g. using ConfigEntityRegistry)
|
|
|
|
The Entity Snapshot Ingest endpoints allow you to ingest multiple aspects about a particular entity at the same time.
|
|
|
|
##### Create a user
|
|
|
|
```
|
|
curl 'http://localhost:8080/entities?action=ingest' -X POST --data '{
|
|
"entity":{
|
|
"value":{
|
|
"com.linkedin.metadata.snapshot.CorpUserSnapshot":{
|
|
"urn":"urn:li:corpuser:footbarusername",
|
|
"aspects":[
|
|
{
|
|
"com.linkedin.identity.CorpUserInfo":{
|
|
"active":true,
|
|
"displayName":"Foo Bar",
|
|
"fullName":"Foo Bar",
|
|
"email":"fbar@linkedin.com"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
}'
|
|
```
|
|
|
|
##### Create a group
|
|
|
|
```
|
|
curl 'http://localhost:8080/entities?action=ingest' -X POST --data '{
|
|
"entity":{
|
|
"value":{
|
|
"com.linkedin.metadata.snapshot.CorpGroupSnapshot":{
|
|
"urn":"urn:li:corpGroup:dev",
|
|
"aspects":[
|
|
{
|
|
"com.linkedin.identity.CorpGroupInfo":{
|
|
"email":"dev@linkedin.com",
|
|
"admins":[
|
|
"urn:li:corpUser:jdoe"
|
|
],
|
|
"members":[
|
|
"urn:li:corpUser:datahub",
|
|
"urn:li:corpUser:jdoe"
|
|
],
|
|
"groups":[
|
|
|
|
]
|
|
}
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
}'
|
|
```
|
|
|
|
##### Create a dataset
|
|
|
|
```
|
|
curl 'http://localhost:8080/entities?action=ingest' -X POST --data '{
|
|
"entity":{
|
|
"value":{
|
|
"com.linkedin.metadata.snapshot.DatasetSnapshot":{
|
|
"urn":"urn:li:dataset:(urn:li:dataPlatform:foo,bar,PROD)",
|
|
"aspects":[
|
|
{
|
|
"com.linkedin.common.Ownership":{
|
|
"owners":[
|
|
{
|
|
"owner":"urn:li:corpuser:fbar",
|
|
"type":"DATAOWNER"
|
|
}
|
|
],
|
|
"lastModified":{
|
|
"time":0,
|
|
"actor":"urn:li:corpuser:fbar"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"com.linkedin.common.InstitutionalMemory":{
|
|
"elements":[
|
|
{
|
|
"url":"https://www.linkedin.com",
|
|
"description":"Sample doc",
|
|
"createStamp":{
|
|
"time":0,
|
|
"actor":"urn:li:corpuser:fbar"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"com.linkedin.schema.SchemaMetadata":{
|
|
"schemaName":"FooEvent",
|
|
"platform":"urn:li:dataPlatform:foo",
|
|
"version":0,
|
|
"created":{
|
|
"time":0,
|
|
"actor":"urn:li:corpuser:fbar"
|
|
},
|
|
"lastModified":{
|
|
"time":0,
|
|
"actor":"urn:li:corpuser:fbar"
|
|
},
|
|
"hash":"",
|
|
"platformSchema":{
|
|
"com.linkedin.schema.KafkaSchema":{
|
|
"documentSchema":"{\"type\":\"record\",\"name\":\"MetadataChangeEvent\",\"namespace\":\"com.linkedin.mxe\",\"doc\":\"Kafka event for proposing a metadata change for an entity.\",\"fields\":[{\"name\":\"auditHeader\",\"type\":{\"type\":\"record\",\"name\":\"KafkaAuditHeader\",\"namespace\":\"com.linkedin.avro2pegasus.events\",\"doc\":\"Header\"}}]}"
|
|
}
|
|
},
|
|
"fields":[
|
|
{
|
|
"fieldPath":"foo",
|
|
"description":"Bar",
|
|
"nativeDataType":"string",
|
|
"type":{
|
|
"type":{
|
|
"com.linkedin.schema.StringType":{
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
}'
|
|
```
|
|
|
|
##### Create a chart
|
|
|
|
```
|
|
curl 'http://localhost:8080/entities?action=ingest' -X POST --data '{
|
|
"entity":{
|
|
"value":{
|
|
"com.linkedin.metadata.snapshot.ChartSnapshot":{
|
|
"urn":"urn:li:chart:(looker,baz1)",
|
|
"aspects":[
|
|
{
|
|
"com.linkedin.chart.ChartInfo":{
|
|
"title":"Baz Chart 1",
|
|
"description":"Baz Chart 1",
|
|
"inputs":[
|
|
{
|
|
"string":"urn:li:dataset:(urn:li:dataPlatform:hdfs,SampleHdfsDataset,PROD)"
|
|
}
|
|
],
|
|
"lastModified":{
|
|
"created":{
|
|
"time":0,
|
|
"actor":"urn:li:corpuser:jdoe"
|
|
},
|
|
"lastModified":{
|
|
"time":0,
|
|
"actor":"urn:li:corpuser:datahub"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
}'
|
|
```
|
|
|
|
##### Create a dashboard
|
|
|
|
```
|
|
curl 'http://localhost:8080/entities?action=ingest' -X POST --data '{
|
|
"entity":{
|
|
"value":{
|
|
"com.linkedin.metadata.snapshot.DashboardSnapshot":{
|
|
"urn":"urn:li:dashboard:(looker,baz)",
|
|
"aspects":[
|
|
{
|
|
"com.linkedin.dashboard.DashboardInfo":{
|
|
"title":"Baz Dashboard",
|
|
"description":"Baz Dashboard",
|
|
"charts":[
|
|
"urn:li:chart:(looker,baz1)",
|
|
"urn:li:chart:(looker,baz2)"
|
|
],
|
|
"lastModified":{
|
|
"created":{
|
|
"time":0,
|
|
"actor":"urn:li:corpuser:jdoe"
|
|
},
|
|
"lastModified":{
|
|
"time":0,
|
|
"actor":"urn:li:corpuser:datahub"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
}'
|
|
```
|
|
|
|
##### Create Tags
|
|
|
|
To create a new tag called "Engineering", we can use the following curl.
|
|
|
|
```
|
|
curl 'http://localhost:8080/entities?action=ingest' -X POST --data '{
|
|
"entity":{
|
|
"value":{
|
|
"com.linkedin.metadata.snapshot.TagSnapshot":{
|
|
"urn":"urn:li:tag:Engineering",
|
|
"aspects":[
|
|
{
|
|
"com.linkedin.tag.TagProperties":{
|
|
"name":"Engineering",
|
|
"description":"The tag will be assigned to all assets owned by the Eng org."
|
|
}
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
}'
|
|
```
|
|
|
|
This tag can subsequently be associated with a Data Asset using the "Global Tags" aspect associated with each. For example,
|
|
to add a tag to a Dataset, you can use the following CURL:
|
|
|
|
```
|
|
curl 'http://localhost:8080/entities?action=ingest' -X POST --data '{
|
|
"entity":{
|
|
"value":{
|
|
"com.linkedin.metadata.snapshot.DatasetSnapshot":{
|
|
"urn":"urn:li:dataset:(urn:li:dataPlatform:foo,bar,PROD)",
|
|
"aspects":[
|
|
{
|
|
"com.linkedin.common.GlobalTags":{
|
|
"tags":[
|
|
{
|
|
"tag":"urn:li:tag:Engineering"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
}'
|
|
```
|
|
|
|
And to add the tag to a field in a particular Dataset's schema, you can use a CURL to update the EditableSchemaMetadata Aspect:
|
|
|
|
```
|
|
curl 'http://localhost:8080/entities?action=ingest' -X POST --data '{
|
|
"entity":{
|
|
"value":{
|
|
"com.linkedin.metadata.snapshot.DatasetSnapshot":{
|
|
"urn":"urn:li:dataset:(urn:li:dataPlatform:foo,bar,PROD)",
|
|
"aspects":[
|
|
{
|
|
"com.linkedin.schema.EditableSchemaMetadata": {
|
|
"editableSchemaFieldInfo":[
|
|
{
|
|
"fieldPath":"myFieldName",
|
|
"globalTags": {
|
|
"tags":[
|
|
{
|
|
"tag":"urn:li:tag:Engineering"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
]
|
|
}
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
}'
|
|
```
|
|
|
|
##### Soft Deleting an Entity
|
|
|
|
DataHub uses a special "Status" aspect associated with each entity to represent the lifecycle state of an Entity.
|
|
To soft delete an entire Entity, you can use the special "Status" aspect. Note that soft deletion means that
|
|
an entity will not be discoverable via Search or Browse, but its entity page will still be viewable.
|
|
|
|
For example, to delete a particular chart:
|
|
|
|
```
|
|
curl 'http://localhost:8080/entities?action=ingest' -X POST --data '{
|
|
"entity":{
|
|
"value":{
|
|
"com.linkedin.metadata.snapshot.ChartSnapshot":{
|
|
"aspects":[
|
|
{
|
|
"com.linkedin.common.Status":{
|
|
"removed": true
|
|
}
|
|
}
|
|
],
|
|
"urn":"urn:li:chart:(looker,baz1)"
|
|
}
|
|
}
|
|
}
|
|
}'
|
|
```
|
|
|
|
To re-enable the Entity, you can make a similar request:
|
|
|
|
```
|
|
curl 'http://localhost:8080/entities?action=ingest' -X POST --data '{
|
|
"entity":{
|
|
"value":{
|
|
"com.linkedin.metadata.snapshot.ChartSnapshot":{
|
|
"aspects":[
|
|
{
|
|
"com.linkedin.common.Status":{
|
|
"removed": false
|
|
}
|
|
}
|
|
],
|
|
"urn":"urn:li:chart:(looker,baz1)"
|
|
}
|
|
}
|
|
}
|
|
}'
|
|
```
|
|
|
|
To issue a hard delete or soft-delete, or undo a particular ingestion run, you can use the [DataHub CLI](docs/how/delete-metadata.md).
|
|
|
|
#### Retrieving Entity Aspects
|
|
|
|
Simply curl the `entitiesV2` endpoint of GMS:
|
|
|
|
```
|
|
curl 'http://localhost:8080/entitiesV2/<url-encoded-entity-urn>'
|
|
```
|
|
|
|
For example, to retrieve the latest aspects associated with the "SampleHdfsDataset" `Dataset`:
|
|
|
|
```
|
|
curl --header 'X-RestLi-Protocol-Version: 2.0.0' 'http://localhost:8080/entitiesV2/urn%3Ali%3Adataset%3A%28urn%3Ali%3AdataPlatform%3Ahdfs%2CSampleHdfsDataset%2CPROD%29'
|
|
```
|
|
|
|
**Example Response**
|
|
|
|
```json
|
|
{
|
|
"urn": "urn:li:dataset:(urn:li:dataPlatform:hdfs,SampleHdfsDataset,PROD)",
|
|
"aspects": {
|
|
"editableSchemaMetadata": {
|
|
"name": "editableSchemaMetadata",
|
|
"version": 0,
|
|
"value": {
|
|
"created": {
|
|
"actor": "urn:li:corpuser:jdoe",
|
|
"time": 1581407189000
|
|
},
|
|
"editableSchemaFieldInfo": [
|
|
{
|
|
"fieldPath": "shipment_info",
|
|
"globalTags": {
|
|
"tags": [
|
|
{
|
|
"tag": "urn:li:tag:Legacy"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
],
|
|
"lastModified": {
|
|
"actor": "urn:li:corpuser:jdoe",
|
|
"time": 1581407189000
|
|
}
|
|
},
|
|
"created": {
|
|
"actor": "urn:li:corpuser:UNKNOWN",
|
|
"time": 1646245614843
|
|
}
|
|
},
|
|
"browsePaths": {
|
|
"name": "browsePaths",
|
|
"version": 0,
|
|
"value": {
|
|
"paths": ["/prod/hdfs/SampleHdfsDataset"]
|
|
},
|
|
"created": {
|
|
"actor": "urn:li:corpuser:UNKNOWN",
|
|
"time": 1646245614843
|
|
}
|
|
},
|
|
"datasetKey": {
|
|
"name": "datasetKey",
|
|
"version": 0,
|
|
"value": {
|
|
"name": "SampleHdfsDataset",
|
|
"platform": "urn:li:dataPlatform:hdfs",
|
|
"origin": "PROD"
|
|
},
|
|
"created": {
|
|
"actor": "urn:li:corpuser:UNKNOWN",
|
|
"time": 1646245614843
|
|
}
|
|
},
|
|
"ownership": {
|
|
"name": "ownership",
|
|
"version": 0,
|
|
"value": {
|
|
"owners": [
|
|
{
|
|
"owner": "urn:li:corpuser:jdoe",
|
|
"type": "DATAOWNER"
|
|
},
|
|
{
|
|
"owner": "urn:li:corpuser:datahub",
|
|
"type": "DATAOWNER"
|
|
}
|
|
],
|
|
"lastModified": {
|
|
"actor": "urn:li:corpuser:jdoe",
|
|
"time": 1581407189000
|
|
}
|
|
},
|
|
"created": {
|
|
"actor": "urn:li:corpuser:UNKNOWN",
|
|
"time": 1646245614843
|
|
}
|
|
},
|
|
"dataPlatformInstance": {
|
|
"name": "dataPlatformInstance",
|
|
"version": 0,
|
|
"value": {
|
|
"platform": "urn:li:dataPlatform:hdfs"
|
|
},
|
|
"created": {
|
|
"actor": "urn:li:corpuser:UNKNOWN",
|
|
"time": 1646245614843
|
|
}
|
|
},
|
|
"institutionalMemory": {
|
|
"name": "institutionalMemory",
|
|
"version": 0,
|
|
"value": {
|
|
"elements": [
|
|
{
|
|
"createStamp": {
|
|
"actor": "urn:li:corpuser:jdoe",
|
|
"time": 1581407189000
|
|
},
|
|
"description": "Sample doc",
|
|
"url": "https://www.linkedin.com"
|
|
}
|
|
]
|
|
},
|
|
"created": {
|
|
"actor": "urn:li:corpuser:UNKNOWN",
|
|
"time": 1646245614843
|
|
}
|
|
},
|
|
"schemaMetadata": {
|
|
"name": "schemaMetadata",
|
|
"version": 0,
|
|
"value": {
|
|
"created": {
|
|
"actor": "urn:li:corpuser:jdoe",
|
|
"time": 1581407189000
|
|
},
|
|
"platformSchema": {
|
|
"com.linkedin.schema.KafkaSchema": {
|
|
"documentSchema": "{\"type\":\"record\",\"name\":\"SampleHdfsSchema\",\"namespace\":\"com.linkedin.dataset\",\"doc\":\"Sample HDFS dataset\",\"fields\":[{\"name\":\"field_foo\",\"type\":[\"string\"]},{\"name\":\"field_bar\",\"type\":[\"boolean\"]}]}"
|
|
}
|
|
},
|
|
"lastModified": {
|
|
"actor": "urn:li:corpuser:jdoe",
|
|
"time": 1581407189000
|
|
},
|
|
"schemaName": "SampleHdfsSchema",
|
|
"fields": [
|
|
{
|
|
"nullable": false,
|
|
"fieldPath": "shipment_info",
|
|
"description": "Shipment info description",
|
|
"isPartOfKey": false,
|
|
"type": {
|
|
"type": {
|
|
"com.linkedin.schema.RecordType": {}
|
|
}
|
|
},
|
|
"nativeDataType": "varchar(100)",
|
|
"recursive": false
|
|
},
|
|
{
|
|
"nullable": false,
|
|
"fieldPath": "shipment_info.date",
|
|
"description": "Shipment info date description",
|
|
"isPartOfKey": false,
|
|
"type": {
|
|
"type": {
|
|
"com.linkedin.schema.DateType": {}
|
|
}
|
|
},
|
|
"nativeDataType": "Date",
|
|
"recursive": false
|
|
},
|
|
{
|
|
"nullable": false,
|
|
"fieldPath": "shipment_info.target",
|
|
"description": "Shipment info target description",
|
|
"isPartOfKey": false,
|
|
"type": {
|
|
"type": {
|
|
"com.linkedin.schema.StringType": {}
|
|
}
|
|
},
|
|
"nativeDataType": "text",
|
|
"recursive": false
|
|
},
|
|
{
|
|
"nullable": false,
|
|
"fieldPath": "shipment_info.destination",
|
|
"description": "Shipment info destination description",
|
|
"isPartOfKey": false,
|
|
"type": {
|
|
"type": {
|
|
"com.linkedin.schema.StringType": {}
|
|
}
|
|
},
|
|
"nativeDataType": "varchar(100)",
|
|
"recursive": false
|
|
},
|
|
{
|
|
"nullable": false,
|
|
"fieldPath": "shipment_info.geo_info",
|
|
"description": "Shipment info geo_info description",
|
|
"isPartOfKey": false,
|
|
"type": {
|
|
"type": {
|
|
"com.linkedin.schema.RecordType": {}
|
|
}
|
|
},
|
|
"nativeDataType": "varchar(100)",
|
|
"recursive": false
|
|
},
|
|
{
|
|
"nullable": false,
|
|
"fieldPath": "shipment_info.geo_info.lat",
|
|
"description": "Shipment info geo_info lat",
|
|
"isPartOfKey": false,
|
|
"type": {
|
|
"type": {
|
|
"com.linkedin.schema.NumberType": {}
|
|
}
|
|
},
|
|
"nativeDataType": "float",
|
|
"recursive": false
|
|
},
|
|
{
|
|
"nullable": false,
|
|
"fieldPath": "shipment_info.geo_info.lng",
|
|
"description": "Shipment info geo_info lng",
|
|
"isPartOfKey": false,
|
|
"type": {
|
|
"type": {
|
|
"com.linkedin.schema.NumberType": {}
|
|
}
|
|
},
|
|
"nativeDataType": "float",
|
|
"recursive": false
|
|
}
|
|
],
|
|
"version": 0,
|
|
"hash": "",
|
|
"platform": "urn:li:dataPlatform:hdfs"
|
|
},
|
|
"created": {
|
|
"actor": "urn:li:corpuser:UNKNOWN",
|
|
"time": 1646245614843
|
|
}
|
|
},
|
|
"upstreamLineage": {
|
|
"name": "upstreamLineage",
|
|
"version": 0,
|
|
"value": {
|
|
"upstreams": [
|
|
{
|
|
"auditStamp": {
|
|
"actor": "urn:li:corpuser:jdoe",
|
|
"time": 1581407189000
|
|
},
|
|
"type": "TRANSFORMED",
|
|
"dataset": "urn:li:dataset:(urn:li:dataPlatform:kafka,SampleKafkaDataset,PROD)"
|
|
}
|
|
]
|
|
},
|
|
"created": {
|
|
"actor": "urn:li:corpuser:UNKNOWN",
|
|
"time": 1646245614843
|
|
}
|
|
}
|
|
},
|
|
"entityName": "dataset"
|
|
}
|
|
```
|
|
|
|
You can also optionally limit to specific aspects using the `aspects` query parameter:
|
|
|
|
```
|
|
curl 'http://localhost:8080/entitiesV2/<url-encoded-entity-urn>?aspects=List(upstreamLineage)'
|
|
```
|
|
|
|
#### Retrieving Entities (Legacy)
|
|
|
|
> Note that this method of retrieving entities is deprecated, as it uses the legacy Snapshot models. Please refer to the **Retriving Entity Aspects** section above for the
|
|
> latest guidance.
|
|
|
|
The Entity Snapshot Get APIs allow to retrieve the latest version of each aspect associated with an Entity.
|
|
|
|
In general, when reading entities by primary key (urn), you will use the general-purpose `entities` endpoints. To fetch by primary key (urn), you'll
|
|
issue a query of the following form:
|
|
|
|
```
|
|
curl 'http://localhost:8080/entities/<url-encoded-entity-urn>'
|
|
```
|
|
|
|
##### Get a CorpUser
|
|
|
|
```
|
|
curl 'http://localhost:8080/entities/urn%3Ali%3Acorpuser%3Afbar'
|
|
|
|
{
|
|
"value":{
|
|
"com.linkedin.metadata.snapshot.CorpUserSnapshot":{
|
|
"urn":"urn:li:corpuser:fbar",
|
|
"aspects":[
|
|
{
|
|
"com.linkedin.metadata.key.CorpUserKey":{
|
|
"username":"fbar"
|
|
}
|
|
},
|
|
{
|
|
"com.linkedin.identity.CorpUserInfo":{
|
|
"active":true,
|
|
"fullName":"Foo Bar",
|
|
"displayName":"Foo Bar",
|
|
"email":"fbar@linkedin.com"
|
|
}
|
|
},
|
|
{
|
|
"com.linkedin.identity.CorpUserEditableInfo":{
|
|
|
|
}
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
##### Get a CorpGroup
|
|
|
|
```
|
|
curl 'http://localhost:8080/entities/urn%3Ali%3AcorpGroup%3Adev'
|
|
|
|
{
|
|
"value":{
|
|
"com.linkedin.metadata.snapshot.CorpGroupSnapshot":{
|
|
"urn":"urn:li:corpGroup:dev",
|
|
"aspects":[
|
|
{
|
|
"com.linkedin.metadata.key.CorpGroupKey":{
|
|
"name":"dev"
|
|
}
|
|
},
|
|
{
|
|
"com.linkedin.identity.CorpGroupInfo":{
|
|
"groups":[
|
|
|
|
],
|
|
"email":"dev@linkedin.com",
|
|
"admins":[
|
|
"urn:li:corpUser:jdoe"
|
|
],
|
|
"members":[
|
|
"urn:li:corpUser:datahub",
|
|
"urn:li:corpUser:jdoe"
|
|
]
|
|
}
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
##### Get a Dataset
|
|
|
|
```
|
|
curl 'http://localhost:8080/entities/urn%3Ali%3Adataset%3A(urn%3Ali%3AdataPlatform%3Afoo,bar,PROD)'
|
|
|
|
{
|
|
"value":{
|
|
"com.linkedin.metadata.snapshot.DatasetSnapshot":{
|
|
"urn":"urn:li:dataset:(urn:li:dataPlatform:foo,bar,PROD)",
|
|
"aspects":[
|
|
{
|
|
"com.linkedin.metadata.key.DatasetKey":{
|
|
"origin":"PROD",
|
|
"name":"bar",
|
|
"platform":"urn:li:dataPlatform:foo"
|
|
}
|
|
},
|
|
{
|
|
"com.linkedin.common.InstitutionalMemory":{
|
|
"elements":[
|
|
{
|
|
"createStamp":{
|
|
"actor":"urn:li:corpuser:fbar",
|
|
"time":0
|
|
},
|
|
"description":"Sample doc",
|
|
"url":"https://www.linkedin.com"
|
|
}
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"com.linkedin.common.Ownership":{
|
|
"owners":[
|
|
{
|
|
"owner":"urn:li:corpuser:fbar",
|
|
"type":"DATAOWNER"
|
|
}
|
|
],
|
|
"lastModified":{
|
|
"actor":"urn:li:corpuser:fbar",
|
|
"time":0
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"com.linkedin.schema.SchemaMetadata":{
|
|
"created":{
|
|
"actor":"urn:li:corpuser:fbar",
|
|
"time":0
|
|
},
|
|
"platformSchema":{
|
|
"com.linkedin.schema.KafkaSchema":{
|
|
"documentSchema":"{\"type\":\"record\",\"name\":\"MetadataChangeEvent\",\"namespace\":\"com.linkedin.mxe\",\"doc\":\"Kafka event for proposing a metadata change for an entity.\",\"fields\":[{\"name\":\"auditHeader\",\"type\":{\"type\":\"record\",\"name\":\"KafkaAuditHeader\",\"namespace\":\"com.linkedin.avro2pegasus.events\",\"doc\":\"Header\"}}]}"
|
|
}
|
|
},
|
|
"lastModified":{
|
|
"actor":"urn:li:corpuser:fbar",
|
|
"time":0
|
|
},
|
|
"schemaName":"FooEvent",
|
|
"fields":[
|
|
{
|
|
"fieldPath":"foo",
|
|
"description":"Bar",
|
|
"type":{
|
|
"type":{
|
|
"com.linkedin.schema.StringType":{
|
|
|
|
}
|
|
}
|
|
},
|
|
"nativeDataType":"string"
|
|
}
|
|
],
|
|
"version":0,
|
|
"hash":"",
|
|
"platform":"urn:li:dataPlatform:foo"
|
|
}
|
|
},
|
|
{
|
|
"com.linkedin.common.BrowsePaths":{
|
|
"paths":[
|
|
"/prod/foo/bar"
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"com.linkedin.dataset.UpstreamLineage":{
|
|
"upstreams":[
|
|
{
|
|
"auditStamp":{
|
|
"actor":"urn:li:corpuser:fbar",
|
|
"time":0
|
|
},
|
|
"type":"TRANSFORMED",
|
|
"dataset":"urn:li:dataset:(urn:li:dataPlatform:foo,barUp,PROD)"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
##### Get a Chart
|
|
|
|
```
|
|
curl 'http://localhost:8080/entities/urn%3Ali%3Achart%3A(looker,baz1)'
|
|
|
|
{
|
|
"value":{
|
|
"com.linkedin.metadata.snapshot.ChartSnapshot":{
|
|
"urn":"urn:li:chart:(looker,baz1)",
|
|
"aspects":[
|
|
{
|
|
"com.linkedin.metadata.key.ChartKey":{
|
|
"chartId":"baz1",
|
|
"dashboardTool":"looker"
|
|
}
|
|
},
|
|
{
|
|
"com.linkedin.common.BrowsePaths":{
|
|
"paths":[
|
|
"/looker/baz1"
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"com.linkedin.chart.ChartInfo":{
|
|
"description":"Baz Chart 1",
|
|
"lastModified":{
|
|
"created":{
|
|
"actor":"urn:li:corpuser:jdoe",
|
|
"time":0
|
|
},
|
|
"lastModified":{
|
|
"actor":"urn:li:corpuser:datahub",
|
|
"time":0
|
|
}
|
|
},
|
|
"title":"Baz Chart 1",
|
|
"inputs":[
|
|
{
|
|
"string":"urn:li:dataset:(urn:li:dataPlatform:hdfs,SampleHdfsDataset,PROD)"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
##### Get a Dashboard
|
|
|
|
```
|
|
curl 'http://localhost:8080/entities/urn%3Ali%3Adashboard%3A(looker,foo)'
|
|
|
|
{
|
|
"value":{
|
|
"com.linkedin.metadata.snapshot.DashboardSnapshot":{
|
|
"urn":"urn:li:dashboard:(looker,foo)",
|
|
"aspects":[
|
|
{
|
|
"com.linkedin.metadata.key.DashboardKey":{
|
|
"dashboardId":"foo",
|
|
"dashboardTool":"looker"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
##### Get a GlossaryTerm
|
|
|
|
```
|
|
curl 'http://localhost:8080/entities/urn%3Ali%3AglossaryTerm%3A(instruments,instruments.FinancialInstrument_v1)'
|
|
{
|
|
"value":{
|
|
"com.linkedin.metadata.snapshot.GlossaryTermSnapshot":{
|
|
"urn":"urn:li:glossaryTerm:instruments.FinancialInstrument_v1",
|
|
"ownership":{
|
|
"owners":[
|
|
{
|
|
"owner":"urn:li:corpuser:jdoe",
|
|
"type":"DATAOWNER"
|
|
}
|
|
],
|
|
"lastModified":{
|
|
"actor":"urn:li:corpuser:jdoe",
|
|
"time":1581407189000
|
|
}
|
|
},
|
|
"glossaryTermInfo":{
|
|
"definition":"written contract that gives rise to both a financial asset of one entity and a financial liability of another entity",
|
|
"customProperties":{
|
|
"FQDN":"full"
|
|
},
|
|
"sourceRef":"FIBO",
|
|
"sourceUrl":"https://spec.edmcouncil.org/fibo/ontology/FBC/FinancialInstruments/FinancialInstruments/FinancialInstrument",
|
|
"termSource":"EXTERNAL"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
##### Browse an Entity
|
|
|
|
To browse (explore) for an Entity of a particular type (e.g. dataset, chart, etc), you can use the following query format:
|
|
|
|
```
|
|
curl -X POST 'http://localhost:8080/entities?action=browse' \
|
|
--data '{
|
|
"path": "<slash-delimited-browse-path>",
|
|
"entity": "<entity name>",
|
|
"start": 0,
|
|
"limit": 10
|
|
}'
|
|
```
|
|
|
|
For example, to browse the "charts" entity, you could use the following query:
|
|
|
|
```
|
|
curl -X POST 'http://localhost:8080/entities?action=browse' \
|
|
--data '{
|
|
"path": "/looker",
|
|
"entity": "chart",
|
|
"start": 0,
|
|
"limit": 10
|
|
}'
|
|
|
|
{
|
|
"value":{
|
|
"numEntities":1,
|
|
"pageSize":1,
|
|
"metadata":{
|
|
"totalNumEntities":1,
|
|
"groups":[
|
|
|
|
],
|
|
"path":"/looker"
|
|
},
|
|
"from":0,
|
|
"entities":[
|
|
{
|
|
"name":"baz1",
|
|
"urn":"urn:li:chart:(looker,baz1)"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
##### Search an Entity
|
|
|
|
To search for an Entity of a particular type (e.g. dataset, chart, etc), you can use the following query format:
|
|
|
|
```
|
|
curl -X POST 'http://localhost:8080/entities?action=search' \
|
|
--data '{
|
|
"input": "<query-text>",
|
|
"entity": "<entity name>",
|
|
"start": 0,
|
|
"count": 10
|
|
}'
|
|
```
|
|
|
|
The API will return a list of URNs that matched your search query.
|
|
|
|
For example, to search the "charts" entity, you could use the following query:
|
|
|
|
```
|
|
curl -X POST 'http://localhost:8080/entities?action=search' \
|
|
--data '{
|
|
"input": "looker",
|
|
"entity": "chart",
|
|
"start": 0,
|
|
"count": 10
|
|
}'
|
|
|
|
{
|
|
"value":{
|
|
"numEntities":1,
|
|
"pageSize":10,
|
|
"metadata":{
|
|
"urns":[
|
|
"urn:li:chart:(looker,baz1)"
|
|
],
|
|
"matches":[
|
|
{
|
|
"matchedFields":[
|
|
{
|
|
"name":"tool",
|
|
"value":"looker"
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"searchResultMetadatas":[
|
|
{
|
|
"name":"tool",
|
|
"aggregations":{
|
|
"looker":1
|
|
}
|
|
}
|
|
]
|
|
},
|
|
"from":0,
|
|
"entities":[
|
|
"urn:li:chart:(looker,baz1)"
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
###### Exact Match Search
|
|
|
|
You can use colon search for exact match searching on particular @Searchable fields of an Entity.
|
|
|
|
###### Example: Find assets by Tag
|
|
|
|
For example, to fetch all Datasets having a particular tag (Engineering), we can use the following query:
|
|
|
|
```
|
|
curl -X POST 'http://localhost:8080/entities?action=search' \
|
|
--data '{
|
|
"input": "tags:Engineering",
|
|
"entity": "dataset",
|
|
"start": 0,
|
|
"count": 10
|
|
}'
|
|
|
|
{
|
|
"value":{
|
|
"numEntities":1,
|
|
"pageSize":10,
|
|
"metadata":{
|
|
"urns":[
|
|
"urn:li:dataset:(urn:li:dataPlatform:foo,bar,PROD)"
|
|
],
|
|
"matches":[
|
|
{
|
|
"matchedFields":[
|
|
{
|
|
"name":"tags",
|
|
"value":"urn:li:tag:Engineering"
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"searchResultMetadatas":[
|
|
{
|
|
"name":"platform",
|
|
"aggregations":{
|
|
"foo":1
|
|
}
|
|
},
|
|
{
|
|
"name":"origin",
|
|
"aggregations":{
|
|
"PROD":1
|
|
}
|
|
}
|
|
]
|
|
},
|
|
"from":0,
|
|
"entities":[
|
|
"urn:li:dataset:(urn:li:dataPlatform:foo,bar,PROD)"
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
###### Filtering
|
|
|
|
In addition to performing full-text search, you can also filter explicitly against fields marked as @Searchable in the corresponding aspect PDLs.
|
|
|
|
For example, to perform filtering for a chart with title "Baz Chart 1", you could issue the following query:
|
|
|
|
```
|
|
curl -X POST 'http://localhost:8080/entities?action=search' \
|
|
--data '{
|
|
"input": "looker",
|
|
"entity": "chart",
|
|
"start": 0,
|
|
"count": 10,
|
|
"filter": {
|
|
"or": [{
|
|
"and": [
|
|
{
|
|
"field": "title",
|
|
"values": ["Baz Chart 1"],
|
|
"condition": "EQUAL"
|
|
}
|
|
]
|
|
}]
|
|
}
|
|
}'
|
|
|
|
{
|
|
"value":{
|
|
"numEntities":1,
|
|
"pageSize":10,
|
|
"metadata":{
|
|
"urns":[
|
|
"urn:li:chart:(looker,baz1)"
|
|
],
|
|
"matches":[
|
|
{
|
|
"matchedFields":[
|
|
{
|
|
"name":"tool",
|
|
"value":"looker"
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"searchResultMetadatas":[
|
|
{
|
|
"name":"tool",
|
|
"aggregations":{
|
|
"looker":1
|
|
}
|
|
}
|
|
]
|
|
},
|
|
"from":0,
|
|
"entities":[
|
|
"urn:li:chart:(looker,baz1)"
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
where valid conditions include - CONTAIN - END_WITH - EQUAL - IEQUAL (Supports case insensitive equals) - GREATER_THAN - GREATER_THAN_OR_EQUAL_TO - LESS_THAN - LESS_THAN_OR_EQUAL_TO - START_WITH
|
|
|
|
\*Note that the search API only includes data corresponding to the latest snapshots of a particular Entity.
|
|
|
|
##### Autocomplete against fields of an entity
|
|
|
|
To autocomplete a query for a particular entity type, you can use a query of the following form:
|
|
|
|
```
|
|
curl -X POST 'http://localhost:8080/entities?action=autocomplete' \
|
|
--data '{
|
|
"query": "<query-text>",
|
|
"entity": "<entity-name>",
|
|
"limit": 10
|
|
}'
|
|
```
|
|
|
|
For example, to autocomplete a query against all Dataset entities, you could issue the following:
|
|
|
|
```
|
|
curl -X POST 'http://localhost:8080/entities?action=autocomplete' \
|
|
--data '{
|
|
"query": "Baz Ch",
|
|
"entity": "chart",
|
|
"start": 0,
|
|
"limit": 10
|
|
}'
|
|
|
|
{
|
|
"value":{
|
|
"suggestions":[
|
|
"Baz Chart 1"
|
|
],
|
|
"query":"Baz Ch"
|
|
}
|
|
}
|
|
```
|
|
|
|
Note that you can also provide a `Filter` to the autocomplete endpoint:
|
|
|
|
```
|
|
curl -X POST 'http://localhost:8080/entities?action=autocomplete' \
|
|
--data '{
|
|
"query": "Baz C",
|
|
"entity": "chart",
|
|
"start": 0,
|
|
"limit": 10,
|
|
"filter": {
|
|
"or": [{
|
|
"and": [
|
|
{
|
|
"field": "tool",
|
|
"values": ["looker"],
|
|
"condition": "EQUAL"
|
|
}
|
|
]
|
|
}]
|
|
}
|
|
}'
|
|
|
|
{
|
|
"value":{
|
|
"suggestions":[
|
|
"Baz Chart 1"
|
|
],
|
|
"query":"Baz Ch"
|
|
}
|
|
}
|
|
```
|
|
|
|
\*Note that the autocomplete API only includes data corresponding to the latest snapshots of a particular Entity.
|
|
|
|
##### Get a Versioned Aspect
|
|
|
|
In addition to fetching the set of latest Snapshot aspects for an entity, we also support doing a point lookup of an entity at a particular version.
|
|
|
|
To do so, you can use the following query template:
|
|
|
|
```
|
|
curl 'http://localhost:8080/aspects/<url-encoded-entity-urn>?aspect=<aspect-name>&version=<version>
|
|
```
|
|
|
|
Which will return a VersionedAspect, which is a record containing a version and an aspect inside a Rest.li Union, wherein the fully-qualified record name of the
|
|
aspect is the key for the union.
|
|
|
|
For example, to fetch the latest version of a Dataset's "schemaMetadata" aspect, you could issue the following query:
|
|
|
|
```
|
|
curl 'http://localhost:8080/aspects/urn%3Ali%3Adataset%3A(urn%3Ali%3AdataPlatform%3Afoo%2Cbar%2CPROD)?aspect=schemaMetadata&version=0'
|
|
|
|
{
|
|
"version":0,
|
|
"aspect":{
|
|
"com.linkedin.schema.SchemaMetadata":{
|
|
"created":{
|
|
"actor":"urn:li:corpuser:fbar",
|
|
"time":0
|
|
},
|
|
"platformSchema":{
|
|
"com.linkedin.schema.KafkaSchema":{
|
|
"documentSchema":"{\"type\":\"record\",\"name\":\"MetadataChangeEvent\",\"namespace\":\"com.linkedin.mxe\",\"doc\":\"Kafka event for proposing a metadata change for an entity.\",\"fields\":[{\"name\":\"auditHeader\",\"type\":{\"type\":\"record\",\"name\":\"KafkaAuditHeader\",\"namespace\":\"com.linkedin.avro2pegasus.events\",\"doc\":\"Header\"}}]}"
|
|
}
|
|
},
|
|
"lastModified":{
|
|
"actor":"urn:li:corpuser:fbar",
|
|
"time":0
|
|
},
|
|
"schemaName":"FooEvent",
|
|
"fields":[
|
|
{
|
|
"fieldPath":"foo",
|
|
"description":"Bar",
|
|
"type":{
|
|
"type":{
|
|
"com.linkedin.schema.StringType":{
|
|
|
|
}
|
|
}
|
|
},
|
|
"nativeDataType":"string"
|
|
}
|
|
],
|
|
"version":0,
|
|
"hash":"",
|
|
"platform":"urn:li:dataPlatform:foo"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
Keep in mind that versions increase monotonically _after_ version 0, which represents the latest.
|
|
|
|
Note that this API will soon be deprecated and replaced by the V2 Aspect API, discussed below.
|
|
|
|
##### Get a range of Versioned Aspects
|
|
|
|
_Coming Soon_!
|
|
|
|
##### Get a range of Timeseries Aspects
|
|
|
|
With the introduction of Timeseries Aspects, we've introduced a new API for fetching a series of aspects falling into a particular time range. For this, you'll
|
|
use the `/aspects` endpoint. The V2 APIs are unique in that they return a new type of payload: an "Enveloped Aspect". This is essentially a serialized aspect along with
|
|
some system metadata. The serialized aspect can be in any form, though we currently default to escaped Rest.li-compatible JSON.
|
|
|
|
Callers of the V2 Aspect APIs will be expected to deserialize the aspect payload in the way they see fit. For example, they may bind the deserialized JSON object
|
|
into a strongly typed Rest.li RecordTemplate class (which is what datahub-frontend does). The benefit of doing it this way is thaet we remove the necessity to
|
|
use Rest.li Unions to represent an object which can take on multiple payload forms. It also makes adding and removing aspects from the model easier, a process
|
|
which could theoretically be done at runtime as opposed to at deploy time.
|
|
|
|
To fetch a set of Timeseries Aspects that fall into a particular time range, you can use the following query template:
|
|
|
|
```
|
|
curl -X POST 'http://localhost:8080/aspects?action=getTimeseriesAspectValues' \
|
|
--data '{
|
|
"urn": "<urn>",
|
|
"entity": "<entity-name>",
|
|
"aspect": "<time-series-aspect-name>",
|
|
"startTimeMillis": "<your-start-time-ms>",
|
|
"endTimeMillis": "<your-end-time-ms>"
|
|
}'
|
|
```
|
|
|
|
For example, to fetch "datasetProfile" timeseries aspects for a dataset with urn `urn:li:dataset:(urn:li:dataPlatform:foo,barUp,PROD)`
|
|
that were reported after July 26, 2021 and before July 28, 2021, you could issue the following query:
|
|
|
|
```
|
|
curl -X POST 'http://localhost:8080/aspects?action=getTimeseriesAspectValues' \
|
|
--data '{
|
|
"urn": "urn:li:dataset:(urn:li:dataPlatform:redshift,global_dev.larxynx_carcinoma_data_2020,PROD)",
|
|
"entity": "dataset",
|
|
"aspect": "datasetProfile",
|
|
"startTimeMillis": 1625122800000,
|
|
"endTimeMillis": 1627455600000
|
|
}'
|
|
|
|
{
|
|
"value":{
|
|
"limit":2000,
|
|
"aspectName":"datasetProfile",
|
|
"endTimeMillis":1627455600000,
|
|
"startTimeMillis":1625122800000,
|
|
"entityName":"dataset",
|
|
"values":[
|
|
{
|
|
"aspect":{
|
|
"value":"{\"timestampMillis\":1626912000000,\"fieldProfiles\":[{\"uniqueProportion\":1.0,\"sampleValues\":[\"123MMKK12\",\"13KDFMKML\",\"123NNJJJL\"],\"fieldPath\":\"id\",\"nullCount\":0,\"nullProportion\":0.0,\"uniqueCount\":3742},{\"uniqueProportion\":1.0,\"min\":\"1524406400000\",\"max\":\"1624406400000\",\"sampleValues\":[\"1640023230002\",\"1640343012207\",\"16303412330117\"],\"mean\":\"1555406400000\",\"fieldPath\":\"date\",\"nullCount\":0,\"nullProportion\":0.0,\"uniqueCount\":3742},{\"uniqueProportion\":0.037,\"min\":\"21\",\"median\":\"68\",\"max\":\"92\",\"sampleValues\":[\"45\",\"65\",\"81\"],\"mean\":\"65\",\"distinctValueFrequencies\":[{\"value\":\"12\",\"frequency\":103},{\"value\":\"54\",\"frequency\":12}],\"fieldPath\":\"patient_age\",\"nullCount\":0,\"nullProportion\":0.0,\"uniqueCount\":79},{\"uniqueProportion\":0.00820873786407767,\"sampleValues\":[\"male\",\"female\"],\"fieldPath\":\"patient_gender\",\"nullCount\":120,\"nullProportion\":0.03,\"uniqueCount\":2}],\"rowCount\":3742,\"columnCount\":4}",
|
|
"contentType":"application/json"
|
|
}
|
|
},
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
You'll notice that in this API (V2), we return a generic serialized aspect string as opposed to an inlined Rest.li-serialized Snapshot Model.
|
|
|
|
This is part of an initiative to move from MCE + MAE to MetadataChangeProposal and MetadataChangeLog. For more information, see [this doc](docs/advanced/mcp-mcl.md).
|
|
|
|
##### Get Relationships (Edges)
|
|
|
|
To get relationships between entities, you can use the `/relationships` API. Do do so, you must provide the following inputs:
|
|
|
|
1. Urn of the source node
|
|
2. Direction of the edge (INCOMING, OUTGOING)
|
|
3. The name of the Relationship (This can be found in Aspect PDLs within the @Relationship annotation)
|
|
|
|
For example, to get all entities owned by `urn:li:corpuser:fbar`, we could issue the following query:
|
|
|
|
```
|
|
curl 'http://localhost:8080/relationships?direction=INCOMING&urn=urn%3Ali%3Acorpuser%3Auser1&types=OwnedBy'
|
|
```
|
|
|
|
which will return a list of urns, representing entities on the other side of the relationship:
|
|
|
|
```
|
|
{
|
|
"entities":[
|
|
urn:li:dataset:(urn:li:dataPlatform:foo,barUp,PROD)
|
|
]
|
|
}
|
|
```
|
|
|
|
## FAQ
|
|
|
|
_1. How do I find the valid set of Entity names?_
|
|
|
|
Entities are named inside of PDL schemas. Each entity will be annotated with the @Entity annotation, which will include a "name" field inside.
|
|
This represents the "common name" for the entity which can be used in browsing, searching, and more. By default, DataHub ships with the following entities:
|
|
|
|
By convention, all entity PDLs live under `metadata-models/src/main/pegasus/com/linkedin/metadata/snapshot`
|
|
|
|
_2. How do I find the valid set of Aspect names?_
|
|
|
|
Aspects are named inside of PDL schemas. Each aspect will be annotated with the @Aspect annotation, which will include a "name" field inside.
|
|
This represents the "common name" for the entity which can be used in browsing, searching, and more.
|
|
|
|
By convention, all entity PDLs live under `metadata-models/src/main/pegasus/com/linkedin/metadata/common` or `metadata-models/src/main/pegasus/com/linkedin/metadata/<entity-name>`. For example,
|
|
the dataset-specific aspects are located under `metadata-models/src/main/pegasus/com/linkedin/metadata/dataset`.
|
|
|
|
_3. How do I find the valid set of Relationship names?_
|
|
|
|
All relationships are defined on foreign-key fields inside Aspect PDLs. They are reflected by fields bearing the @Relationship annotation. Inside this annotation
|
|
is a "name" field that defines the standardized name of the Relationship to be used when querying.
|
|
|
|
By convention, all entity PDLs live under `metadata-models/src/main/pegasus/com/linkedin/metadata/common` or `metadata-models/src/main/pegasus/com/linkedin/metadata/<entity-name>`. For example,
|
|
the dataset-specific aspects are located under `metadata-models/src/main/pegasus/com/linkedin/metadata/dataset`.
|