Improvements to Metadata Search and System Metadata
Goals:
Improve Metadata Search: This requires redesign of how we store metadata. Design proposed below.
Make search for tags work for all the tags in the list
Support tokenized search where user can search with any word from the value
Schema Search:
CDAP Schema for Datasets, Streams and Views should be stored as metadata and searchable through fieldname or and fieldname with fieldtype (only for primitive fieldtype)
Search filtering based on entity type.
Checklist
User Stories:
Key Value Metadata Search
User should be able to search with key-value or its prefix
User should be able to search with key and individual word in value or its prefix
User should be able to search with just value or its prefix
User should be able to search with individual words in the value
Tag Metadata Search
User should be able to search with tags key and a tag value or its prefix
User should be able to search with just a tag value or its prefix.
Schema Search:
User should be able search with fieldname or its prefix
User should be able to search with fieldname or its prefix scoped just to schema
User should be able to search with fieldname and fieldtype (only for primitive types)
Search Filtering:
User should be able to filter searches to a particular entity type for example app, program, dataset
Partial Searching:
User should be able to see result for individual words in search query.
Design
Search Query Examples:
User stores a key-value metadata with key = "Codename" and value = "Alpha Tango Charlie" for an entity
User can retrieve this entity with the following queries:
key-value
Codename: Alpha Tango Charlie
Codename: Alpha Tang*
key with part of value
Codename: Alpha
Codename: Tango
Codename: Charlie
Codename: Alp*
value
Alpha Tango Charlie
Alpha*
Alpha Tan*
Note:We have decided not to support searches for queries which have parts of value for example "Tango Charlie". You can either search for whole value or with prefix or single words (we plan to tokenize on whitespace)
Individual word in value
Alpha
Tango
Charlie
Alph*
Tan*
Ch*
Not supported:
key* i.e. Codename*
User tags an entity with the following tags "Tag1, Tag22"
User can retrieve this entity with the following queries:
tag key and a tag value:
tags: Tag1
tags: Tag*
a tag value
tag22
tag2*
A dataset has the following schema:
Nested Schema
{ "EmpName": "String", "EmpContact": { "EmpTel": "Integer", "EmpAddr": "String" } }User can retrieve this dataset entity with the following queries:
fieldname:
EmpName
EmpContact
EmpTel
EmpAddr
Emp*
fieldname scoped to schema:
schema: EmpName
schema: EmpContact
schema: EmpTel
schema: EmpAddr
schema: Emp*
fieldname with fieldtype (only for primitive types)
EmpName:String (only for java primitive types)
Note:
We don't plan to support schema searches with complex fieldType. If a user searched with a query which is not scoped with schema by default it will search for schema fields besides the normal key-value and tags.
Open questions:What if an entity has multiple schema (ex: transform which has input and output schema)
We will index both schema (After discussion with Nitin)
How will an user search for a fieldName across input and output schema ?
We do not support searches limited to input/output or just one schema (After discussion with Nitin)
Search Filtering:
User wants to search only for 'dataset'
dataset: Codename: Alpha
dataset: tags: Tag1
dataset: schema: EmpName
Note: if not entity type is specified we will return all matched entities.
Partial Searching:
User searches for "California USA" : Separate every search query on white space and search for every single word (or)
Search result will contain:All entities tagged with "California USA" followed by
All entities tagged with "California" followed by
All entities tagged with "USA"
Storage:
We are going to use the IndexedTable which we are using currently too. In the new storage design we will have two rows:
Value Row: This row will store the entity id with key and value in the value column
Index Row: This row will store the entity id with key (like above) appended by the index which is also stored in the index column. The index column will be used for indexing.
Metadata Storage Format:
Key Column | Value Column |
|---|---|
<VRPrefix><Entity-Id><Key> | Value |
<VRPrefix><Entity-Id><Tags> | Tag1, Tag2, Tag3.... |
<VRPrefix><Entity-Id><Schema> | {Some Schema} |
Index Storage Format:
Key Column | Index Column |
|---|---|
<IRPrefix><Entity-Id><Key><Index> | Index |
<IRPrefix><Entity-Id><Tags><Index> | Index |
<IRPrefix><Entity-Id><Schema><Index> | Index |
This table data represents key-value, tags and schema example discussed above to show how we plan to store the data. Index Column contains all the possibilities of search queries.
Key: Entity with key | Value Column: Value of Metadata (Not Indexed) | Index Column: Indexed value (Indexed) |
|---|---|---|
<VRPrefix><Entity-Id><CodeName> | Alpha Tango Charlie |
|
<VRPrefix><Entity-Id><Tags> | Tag1, Tag22 |
|
<VRPrefix><Entity-Id><Schema> | {EmpName: String, EmpContact: {EmpTel: Integer, EmpAddr: String}} |
|
<IRPrefix><Entity-Id><Codename><CodeName: Alpha Tango Charlie> |
| CodeName: Alpha Tango Charlie |
<IRPrefix><Entity-Id><Codename><Codename: Alpha> |
| Codename: Alpha |
<IRPrefix><Entity-Id><Codename><Codename: Tango> |
| Codename: Tango |
<IRPrefix><Entity-Id><Codename><Codename: Charlie> |
| Codename: Charlie |
<IRPrefix><Entity-Id><Codename><Alpha Tango Charlie> |
| Alpha Tango Charlie |
<IRPrefix><Entity-Id><Codename><Alpha> |
| Alpha |
<IRPrefix><Entity-Id><Codename><Tango> |
| Tango |
<IRPrefix><Entity-Id><Codename><Charlie> |
| Charlie |
<IRPrefix><Entity-Id><tags><tags: Tag1> |
| tags: Tag1 |
<IRPrefix><Entity-Id><tags><tags: Tag22> |
| tags: Tag22 |
<IRPrefix><Entity-Id><tags><Tag1> |
| Tag1 |
<IRPrefix><Entity-Id><tags><Tag22> |
| Tag22 |
<IRPrefix><Entity-Id><schema><schema: EmpName> |
| schema: EmpName |
<IRPrefix><Entity-Id><schema><schema: EmpContact> |
| schema: EmpContact |
<IRPrefix><Entity-Id><schema><schema: EmpTel> |
| schema: EmpTel |
<IRPrefix><Entity-Id><schema><schema: EmpAddr> |
| schema: EmpAddr |
<IRPrefix><Entity-Id><schema><EmpName> |
| EmpName |
<IRPrefix><Entity-Id><schema><EmpContact> |
| EmpContact |
<IRPrefix><Entity-Id><schema><EmpTel> |
| EmpTel |
<IRPrefix><Entity-Id><schema><EmpAddr> |
| EmpAddr |
We will be using the indexedTable like before but now our keys which store values will be prefixed with a special VRPrefix (ValueRowPrefix) and we will store the value in the value column. The indexes will also be stored in the same table and the key will be prefixes with IRPrefix (IndexRowPrefix), the value column for such rows will be empty and the index column will have the index value which will be indexed for search.
Another possibility was to store the real key value in a separate table and the indexes in the indexedTable which will avoid the empty column values for a row but this will lead to 6 tables on total (3 for system and business each) hence we have decided against it.
Search Filtering: We will perform post filtering if the query is limited to an entity type.
In addition to above goals we also plan to do the following:
Here is a list of System Metadata which we are planning to emit from different entities. If you have any suggestions as what other info can be useful as system metadata please comment below.
Artifacts
Applications
Programs
Datasets
Streams
Views
Open Questions:
Additional Requirement and Notes:
Invalidate just * query
Support Pagination of search result in backend
User entity creation time for ordering of search result
Support searched with stemming (workflow/workflows) : Porter Stemming
Support and (&) operation: Example search query - app:appname & program
@Rohit Sinha From product perspective Business Metadata is what makes sense. Business Metadata is always user generated metadata. Preference from product perspective would be Business, but how the implementation names it doesn't matter so much right.