On this page· 3

Read records

  • file format 6
  • Rust SDK 1.0 preview

Goal: read the entities of a pack, then the records whose primary id starts with e1.

Steps

  1. 1. Build a Filter. with_kinds keeps records whose kind is in the list; with_id_prefix keeps records whose primary id starts with the given text.
  2. 2. Pass it to pack.records_filtered(&filter), or call pack.records() for every record.
  3. 3. Call as_entity() or as_relation() on a record to read its members as fields.

Needs the Rust SDK

filter_and_views.rsrust
// Read only some records, and look at entities and relations
// through typed views.
use plxi_sdk::{write, Filter, OpenOptions, Pack, Record};

fn main() -> Result<(), plxi_sdk::Error> {
    let lines = [
        r#"{"k":"ent","id":"e1","t":"Person","name":"Ada","salience":0.5}"#,
        r#"{"k":"ent","id":"e2","t":"Person"}"#,
        r#"{"k":"ent","id":"p1","t":"Place","name":"London"}"#,
        r#"{"k":"rel","src":"e1","tgt":"p1","kind":"lives_in"}"#,
    ];
    let records = lines
        .iter()
        .map(|l| Record::from_json_line(l))
        .collect::<Result<Vec<_>, _>>()?;
    let bytes = write(&records, None)?;
    let pack = Pack::from_bytes(bytes, OpenOptions::default())?;

    // By kind.
    let only_entities = Filter::new().with_kinds(["ent"]);
    let mut names = Vec::new();
    for record in pack.records_filtered(&only_entities) {
        let record = record?;
        let entity = record
            .as_entity()
            .expect("an `ent` record has an entity view");
        let name = entity.name.map(str::to_string);
        names.push((entity.id.to_string(), entity.t.to_string(), name));
    }
    assert_eq!(names.len(), 3);
    let first = (
        "e1".to_string(),
        "Person".to_string(),
        Some("Ada".to_string()),
    );
    assert_eq!(names[0], first);

    // By primary-id prefix. A relation's primary id is "src|tgt|kind".
    let about_e1 = Filter::new().with_id_prefix("e1");
    let ids: Vec<String> = pack
        .records_filtered(&about_e1)
        .map(|r| r.map(|rec| rec.primary_id().to_string()))
        .collect::<Result<_, _>>()?;
    assert_eq!(ids, ["e1", "e1|p1|lives_in"]);

    // Both conditions at once: every field that is set must match.
    let both = Filter::new().with_kinds(["rel"]).with_id_prefix("e1");
    let rels: Vec<Record> =
        pack.records_filtered(&both).collect::<Result<_, _>>()?;
    let view = rels[0]
        .as_relation()
        .expect("a `rel` record has a relation view");
    assert_eq!((view.src, view.tgt, view.kind), ("e1", "p1", "lives_in"));
    println!("{} -[{}]-> {}", view.src, view.kind, view.tgt);
    Ok(())
}
Output
e1 -[lives_in]-> p1

Ran with cargo run --example 03_filter_and_views · exit status 0

Things to know

  • Records come back in file order, which is sort-key order. Each item is a Result<Record>.
  • When both conditions are set, a record must meet both.
  • A relation's primary id is src|tgt|kind, so an id prefix selects relations by their source.
  • Only ent and rel have typed views. Every other kind is read as JSON with Record::to_json_value.
  • An error in the record stream always passes the filter, so a filtered read does not hide a damaged line. A body that is not UTF-8 yields one error and nothing else.
  • Record::json_line returns the writer's spelling of the record, which may differ from the text that was read. Records and kinds

Reference

Sections