public void LoadTurtle(string tfile) { DateTime tt0 = DateTime.Now; // ======== Загрузка первичных ячеек данными ======== otriples.Clear(); otriples.Fill(new object[0]); dtriples.Clear(); dtriples.Fill(new object[0]); literals.Clear(); literals.Fill(new object[0]); int i = 0; foreach (var triple in TripleInt.LoadGraph(tfile)) { if (i % 100000 == 0) { Console.Write("{0} ", i / 100000); } i++; if (triple is OTripleInt) { var tr = (OTripleInt)triple; otriples.Root.AppendElement(new object[] { tr.subject, tr.predicate, tr.obj }); } else { var tr = (DTripleInt)triple; Literal lit = tr.data; object[] da; if (lit.Vid == LiteralVidEnumeration.integer) { da = new object[] { 1, lit.Value } } ; else if (lit.Vid == LiteralVidEnumeration.date) { da = new object[] { 3, lit.Value } } ; else if (lit.Vid == LiteralVidEnumeration.text) { Text t = (Text)lit.Value; da = new object[] { 2, new object[] { t.Value, t.Lang } }; } else { da = new object[] { 0, null } }; var off = literals.Root.AppendElement(da); dtriples.Root.AppendElement(new object[] { tr.subject, tr.predicate, off }); } } otriples.Flush(); dtriples.Flush(); literals.Flush(); // ======== Формирование вторичных ячеек ======== PaCell otriples_op = new PaCell(tp_otriples, path + "otriples_op.pac", false); otriples_op.Clear(); otriples_op.Fill(new object[0]); // Другой вариант - копирование файла otriples.Root.Scan((off, pobj) => { otriples_op.Root.AppendElement(pobj); return(true); }); otriples_op.Flush(); Console.WriteLine("Additional files ok. duration={0}", (DateTime.Now - tt0).Ticks / 10000L); tt0 = DateTime.Now; // ======= Сортировки ======= // Упорядочивание otriples по s-p-o SPOComparer spo_compare = new SPOComparer(); otriples.Root.SortByKey <SubjPredObjInt>(rec => new SubjPredObjInt(rec), spo_compare); Console.WriteLine("otriples.Root.Sort ok. Duration={0} msec.", (DateTime.Now - tt0).Ticks / 10000L); tt0 = DateTime.Now; SPComparer sp_compare = new SPComparer(); // Упорядочивание otriples_op по o-p otriples_op.Root.SortByKey <SubjPredInt>(rec => { object[] r = (object[])rec; return(new SubjPredInt() { pred = (int)r[1], subj = (int)r[2] }); }, sp_compare); Console.WriteLine("otriples_op Sort ok. Duration={0} msec.", (DateTime.Now - tt0).Ticks / 10000L); tt0 = DateTime.Now; // Упорядочивание dtriples_sp по s-p dtriples.Root.SortByKey(rec => { object[] r = (object[])rec; return(new SubjPredInt() { pred = (int)r[1], subj = (int)r[0] }); }, sp_compare); Console.WriteLine("dtriples.Root.Sort ok. Duration={0} msec.", (DateTime.Now - tt0).Ticks / 10000L); tt0 = DateTime.Now; // ==== Определение количества сущностей ==== // Делаю три упрощенных сканера DiapasonScanner <int> i_fields = new DiapasonScanner <int>(dtriples, ent => (int)((object[])ent.Get())[0]); DiapasonScanner <int> i_direct = new DiapasonScanner <int>(otriples, ent => (int)((object[])ent.Get())[0]); DiapasonScanner <int> i_inverse = new DiapasonScanner <int>(otriples_op, ent => (int)((object[])ent.Get())[2]); int n_entities = 0; i_fields.Start(); i_direct.Start(); i_inverse.Start(); while (i_fields.HasValue || i_direct.HasValue || i_inverse.HasValue) { n_entities++; int id0 = i_fields.HasValue ? i_fields.KeyCurrent : Int32.MaxValue; int id1 = i_direct.HasValue ? i_direct.KeyCurrent : Int32.MaxValue; int id2 = i_inverse.HasValue ? i_inverse.KeyCurrent : Int32.MaxValue; // Минимальное значение кода идентификатора int id = Math.Min(id0, Math.Min(id1, id2)); if (id0 == id) { i_fields.Next(); } if (id1 == id) { i_direct.Next(); } if (id2 == id) { i_inverse.Next(); } } Console.WriteLine("Scan3count ok. Duration={0} msec. cnt_e={1} ", (DateTime.Now - tt0).Ticks / 10000L, n_entities); tt0 = DateTime.Now; // ==== Построение дерева слиянием трех ячеек ==== // Делаю три сканера из трех ячеек DiapasonElementsScanner <SubjPredInt> fields = new DiapasonElementsScanner <SubjPredInt>(dtriples, ob => { object[] v = (object[])ob; return(new SubjPredInt() { subj = (int)v[0], pred = (int)v[1] }); }); DiapasonElementsScanner <SubjPredInt> direct = new DiapasonElementsScanner <SubjPredInt>(otriples, ob => { object[] v = (object[])ob; return(new SubjPredInt() { subj = (int)v[0], pred = (int)v[1] }); }); DiapasonElementsScanner <SubjPredInt> inverse = new DiapasonElementsScanner <SubjPredInt>(otriples_op, ob => { object[] v = (object[])ob; return(new SubjPredInt() { subj = (int)v[2], pred = (int)v[1] }); }); // Стартуем сканеры fields.Start(); direct.Start(); inverse.Start(); // Заведем ячейку для результата сканирования tree_fix.Clear(); tree_fix.Root.SetRepeat(n_entities); Console.WriteLine("tree_fix length={0}", tree_fix.Root.Count()); long longindex = 0; int cnt_e = 0; // для отладки long c1 = 0, c2 = 0, c3 = 0; // для отладки //PaEntry ent_dtriples = dtriples.Root.Element(0); // вход для доступа к литералам // Начинаем тройное сканирование while (fields.HasValue || direct.HasValue || inverse.HasValue) { // Здесь у нас НОВОЕ значение идентификатора cnt_e++; if (cnt_e % 10000000 == 0) { Console.Write("{0} ", cnt_e / 10000000); } int id0 = fields.HasValue ? fields.KeyCurrent.subj : Int32.MaxValue; int id1 = direct.HasValue ? direct.KeyCurrent.subj : Int32.MaxValue; int id2 = inverse.HasValue ? inverse.KeyCurrent.subj : Int32.MaxValue; // Минимальное значение кода идентификатора int id = Math.Min(id0, Math.Min(id1, id2)); // массив для получения "однородных" элементов из сканнеров object[] elements; List <object[]> list_fields = new List <object[]>(); while (fields.HasValue && fields.KeyCurrent.subj == id) { int su = fields.KeyCurrent.subj; int pr = fields.KeyCurrent.pred; var diap = fields.Next(out elements); c3 += diap.numb; list_fields.AddRange(elements.Cast <object[]>().Select(e3 => new object[] { e3[1], e3[2] })); } List <object[]> list_direct = new List <object[]>(); while (direct.HasValue && direct.KeyCurrent.subj == id) { int su = direct.KeyCurrent.subj; int pr = direct.KeyCurrent.pred; var diap = direct.Next(out elements); c1 += diap.numb; list_direct.AddRange(elements.Cast <object[]>().Select(e3 => new object[] { e3[1], e3[2] })); } List <object[]> list_inverse = new List <object[]>(); while (inverse.HasValue && inverse.KeyCurrent.subj == id) { int su = inverse.KeyCurrent.subj; int pr = inverse.KeyCurrent.pred; var diap = inverse.Next(out elements); c2 += diap.numb; object[] pr_sources_pair = new object[2]; pr_sources_pair[0] = pr; pr_sources_pair[1] = elements.Cast <object[]>().Select(e3 => e3[0]).ToArray(); list_inverse.Add(pr_sources_pair); } //Собираем полную запись object[] record = new object[] { id, list_fields.ToArray(), list_direct.ToArray(), list_inverse.ToArray() }; // Записываем в качестве элемента последовательности tree_fix.Root.Element(longindex).Set(record); longindex++; } tree_fix.Close(); Console.WriteLine("tree_fix ok. Duration={0} msec.", (DateTime.Now - tt0).Ticks / 10000L); tt0 = DateTime.Now; otriples.Close(); otriples_op.Close(); dtriples.Close(); literals.Close(); }
public static IEnumerable <TripleInt> LoadGraph(string datafile) { int ntriples = 0; string subject = null; Dictionary <string, string> namespaces = new Dictionary <string, string>(); System.IO.StreamReader sr = new System.IO.StreamReader(datafile); int count = 2000000000; for (int i = 0; i < count; i++) { string line = sr.ReadLine(); //if (i % 10000 == 0) { Console.Write("{0} ", i / 10000); } if (line == null) { break; } if (line == "") { continue; } if (line[0] == '@') { // namespace string[] parts = line.Split(' '); if (parts.Length != 4 || parts[0] != "@prefix" || parts[3] != ".") { Console.WriteLine("Err: strange line: " + line); continue; } string pref = parts[1]; string nsname = parts[2]; if (nsname.Length < 3 || nsname[0] != '<' || nsname[nsname.Length - 1] != '>') { Console.WriteLine("Err: strange nsname: " + nsname); continue; } nsname = nsname.Substring(1, nsname.Length - 2); namespaces.Add(pref, nsname); } else if (line[0] != ' ') { // Subject line = line.Trim(); subject = GetEntityString(namespaces, line); if (subject == null) { continue; } } else { // Predicate and object string line1 = line.Trim(); int first_blank = line1.IndexOf(' '); if (first_blank == -1) { Console.WriteLine("Err in line: " + line); continue; } string pred_line = line1.Substring(0, first_blank); string predicate = GetEntityString(namespaces, pred_line); string rest_line = line1.Substring(first_blank + 1).Trim(); // Уберем последний символ rest_line = rest_line.Substring(0, rest_line.Length - 1).Trim(); bool isDatatype = rest_line[0] == '\"'; // объект может быть entity или данное, у данного может быть языковый спецификатор или тип string entity = null; string sdata = null; string datatype = null; string lang = null; if (isDatatype) { // Последняя двойная кавычка int lastqu = rest_line.LastIndexOf('\"'); // Значение данных sdata = rest_line.Substring(1, lastqu - 1); // Языковый специализатор: int dog = rest_line.LastIndexOf('@'); if (dog == lastqu + 1) { lang = rest_line.Substring(dog + 1, rest_line.Length - dog - 1); } int pp = rest_line.IndexOf("^^"); if (pp == lastqu + 1) { // Тип данных string qname = rest_line.Substring(pp + 2); // тип данных может быть "префиксным" или полным if (qname[0] == '<') { datatype = qname.Substring(1, qname.Length - 2); } else { datatype = GetEntityString(namespaces, qname); } } yield return(new DTripleInt() { subject = TripleInt.Code(subject), predicate = TripleInt.Code(predicate), data = // d datatype == "http://www.w3.org/2001/XMLSchema#integer" ? new Literal() { Vid = LiteralVidEnumeration.integer, Value = int.Parse(sdata) } : (datatype == "http://www.w3.org/2001/XMLSchema#date" ? new Literal() { Vid = LiteralVidEnumeration.date, Value = DateTime.Parse(sdata).ToBinary() } : (new Literal() { Vid = LiteralVidEnumeration.text, Value = new Text() { Value = sdata, Lang = "en" } })) }); } else { // entity entity = rest_line[0] == '<' ? rest_line.Substring(1, rest_line.Length - 2) : GetEntityString(namespaces, rest_line); yield return(new OTripleInt() { subject = TripleInt.Code(subject), predicate = TripleInt.Code(predicate), obj = TripleInt.Code(entity) }); } ntriples++; } } Console.WriteLine("ntriples={0}", ntriples); }