/// <summary> /// Command-line tool. /// </summary> public static void Main(string[] args) { bool printTree = false; string path = null; for (int i = 0; i < args.Length; i++) { if (args[i].Equals("-printTree")) { printTree = true; } else { path = args[i]; } } if (args.Length != (printTree ? 2 : 1)) { // LUCENENET TODO: Usage depends on wrapping this into a console application assembly. Console.WriteLine("\nUsage: java -classpath ... org.apache.lucene.facet.util.PrintTaxonomyStats [-printTree] /path/to/taxononmy/index\n"); Environment.Exit(1); } Store.Directory dir = FSDirectory.Open(new DirectoryInfo(path)); var r = new DirectoryTaxonomyReader(dir); PrintStats(r, System.Console.Out, printTree); r.Dispose(); //dir.close(); }
public bool? Call() { if (indexReader == null) { indexReader = DirectoryReader.Open(indexDir); lastIndexGeneration = indexReader.IndexCommit.Generation; taxoReader = new DirectoryTaxonomyReader(taxoDir); } else { // verify search index DirectoryReader newReader = DirectoryReader.OpenIfChanged(indexReader); assertNotNull("should not have reached here if no changes were made to the index", newReader); long newGeneration = newReader.IndexCommit.Generation; assertTrue("expected newer generation; current=" + lastIndexGeneration + " new=" + newGeneration, newGeneration > lastIndexGeneration); indexReader.Dispose(); indexReader = newReader; lastIndexGeneration = newGeneration; TestUtil.CheckIndex(indexDir); // verify taxonomy index DirectoryTaxonomyReader newTaxoReader = TaxonomyReader.OpenIfChanged(taxoReader); if (newTaxoReader != null) { taxoReader.Dispose(); taxoReader = newTaxoReader; } TestUtil.CheckIndex(taxoDir); // verify faceted search int id = int.Parse(indexReader.IndexCommit.UserData[VERSION_ID], NumberStyles.HexNumber); IndexSearcher searcher = new IndexSearcher(indexReader); FacetsCollector fc = new FacetsCollector(); searcher.Search(new MatchAllDocsQuery(), fc); Facets facets = new FastTaxonomyFacetCounts(taxoReader, config, fc); assertEquals(1, (int)facets.GetSpecificValue("A", id.ToString("X"))); DrillDownQuery drillDown = new DrillDownQuery(config); drillDown.Add("A", id.ToString("X")); TopDocs docs = searcher.Search(drillDown, 10); assertEquals(1, docs.TotalHits); } return null; }
/// <summary> /// Search engine search provider, used to search indexed documents. /// </summary> /// <param name="directoryIndexInfos">The array directory infomation where the index files are located.</param> /// <param name="directoryFacetInfo">The directory infomation where the facet files are to be placed.</param> public SearchProvider(DirectoryInfo[] directoryIndexInfos, DirectoryInfo directoryFacetInfo) { try { List <Lucene.Net.Index.IndexReader> readers = new List <IndexReader>(); // For each directory. foreach (DirectoryInfo item in directoryIndexInfos) { // Create the index reader. Lucene.Net.Store.Directory directory = FSDirectory.Open(item); Lucene.Net.Index.IndexReader reader = Lucene.Net.Index.DirectoryReader.Open(directory); readers.Add(reader); } // Create the multiple index readers. _reader = new Lucene.Net.Index.MultiReader(readers.ToArray(), true); // Create the facet reader. Lucene.Net.Store.Directory directoryFacet = FSDirectory.Open(directoryFacetInfo); _facetReader = new DirectoryTaxonomyReader(directoryFacet); } catch (Exception) { if (_reader != null) { _reader.Dispose(); } if (_facetReader != null) { _facetReader.Dispose(); } throw; } }
public virtual void TestWriterParent2() { var indexDir = NewDirectory(); var tw = new DirectoryTaxonomyWriter(indexDir); FillTaxonomy(tw); tw.Commit(); var tr = new DirectoryTaxonomyReader(indexDir); CheckWriterParent(tr, tw); tw.Dispose(); tr.Dispose(); indexDir.Dispose(); }
public virtual void TestSeparateReaderAndWriter2() { var indexDir = NewDirectory(); var tw = new DirectoryTaxonomyWriter(indexDir); tw.Commit(); var tr = new DirectoryTaxonomyReader(indexDir); // Test getOrdinal(): FacetLabel author = new FacetLabel("Author"); Assert.AreEqual(1, tr.Count); // the empty taxonomy has size 1 (the root) Assert.AreEqual(TaxonomyReader.INVALID_ORDINAL, tr.GetOrdinal(author)); tw.AddCategory(author); // before commit and refresh, no change: Assert.AreEqual(TaxonomyReader.INVALID_ORDINAL, tr.GetOrdinal(author)); Assert.AreEqual(1, tr.Count); // still root only... Assert.Null(TaxonomyReader.OpenIfChanged(tr)); // this is not enough, because tw.Commit() hasn't been done yet Assert.AreEqual(TaxonomyReader.INVALID_ORDINAL, tr.GetOrdinal(author)); Assert.AreEqual(1, tr.Count); // still root only... tw.Commit(); // still not enough before refresh: Assert.AreEqual(TaxonomyReader.INVALID_ORDINAL, tr.GetOrdinal(author)); Assert.AreEqual(1, tr.Count); // still root only... var newTaxoReader = TaxonomyReader.OpenIfChanged(tr); Assert.NotNull(newTaxoReader); tr.Dispose(); tr = newTaxoReader; Assert.AreEqual(1, tr.GetOrdinal(author)); Assert.AreEqual(2, tr.Count); tw.Dispose(); tr.Dispose(); indexDir.Dispose(); }
public virtual void TestBasic() { Store.Directory dir = NewDirectory(); Store.Directory taxoDir = NewDirectory(); // Writes facet ords to a separate directory from the // main index: DirectoryTaxonomyWriter taxoWriter = new DirectoryTaxonomyWriter(taxoDir, IndexWriterConfig.OpenMode_e.CREATE); RandomIndexWriter writer = new RandomIndexWriter(Random(), dir, Similarity, TimeZone); FacetsConfig config = new FacetsConfig(); // Reused across documents, to add the necessary facet // fields: Document doc = new Document(); doc.Add(new IntField("num", 10, Field.Store.NO)); doc.Add(new FacetField("Author", "Bob")); writer.AddDocument(config.Build(taxoWriter, doc)); doc = new Document(); doc.Add(new IntField("num", 20, Field.Store.NO)); doc.Add(new FacetField("Author", "Lisa")); writer.AddDocument(config.Build(taxoWriter, doc)); doc = new Document(); doc.Add(new IntField("num", 30, Field.Store.NO)); doc.Add(new FacetField("Author", "Lisa")); writer.AddDocument(config.Build(taxoWriter, doc)); doc = new Document(); doc.Add(new IntField("num", 40, Field.Store.NO)); doc.Add(new FacetField("Author", "Susan")); writer.AddDocument(config.Build(taxoWriter, doc)); doc = new Document(); doc.Add(new IntField("num", 45, Field.Store.NO)); doc.Add(new FacetField("Author", "Frank")); writer.AddDocument(config.Build(taxoWriter, doc)); // NRT open IndexSearcher searcher = NewSearcher(writer.Reader); writer.Dispose(); // NRT open var taxoReader = new DirectoryTaxonomyReader(taxoWriter); taxoWriter.Dispose(); // Aggregate the facet counts: FacetsCollector c = new FacetsCollector(); // MatchAllDocsQuery is for "browsing" (counts facets // for all non-deleted docs in the index); normally // you'd use a "normal" query and one of the // Facets.search utility methods: searcher.Search(new MatchAllDocsQuery(), c); TaxonomyFacetSumValueSource facets = new TaxonomyFacetSumValueSource(taxoReader, new FacetsConfig(), c, new IntFieldSource("num")); // Retrieve & verify results: Assert.AreEqual("dim=Author path=[] value=145.0 childCount=4\n Lisa (50.0)\n Frank (45.0)\n Susan (40.0)\n Bob (10.0)\n", facets.GetTopChildren(10, "Author").ToString()); taxoReader.Dispose(); searcher.IndexReader.Dispose(); dir.Dispose(); taxoDir.Dispose(); }
private void AssertConsistentYoungestChild(FacetLabel abPath, int abOrd, int abYoungChildBase1, int abYoungChildBase2, int retry, int numCategories) { var indexDir = new SlowRAMDirectory(-1, null); // no slowness for intialization var tw = new DirectoryTaxonomyWriter(indexDir); tw.AddCategory(new FacetLabel("a", "0")); tw.AddCategory(abPath); tw.Commit(); var tr = new DirectoryTaxonomyReader(indexDir); for (int i = 0; i < numCategories; i++) { var cp = new FacetLabel("a", "b", Convert.ToString(i)); tw.AddCategory(cp); Assert.AreEqual(TaxonomyReader.INVALID_ORDINAL, tr.GetOrdinal(cp), "Ordinal of " + cp + " must be invalid until Taxonomy Reader was refreshed"); } tw.Dispose(); var stop = new AtomicBoolean(false); Exception[] error = new Exception[] { null }; int[] retrieval = new int[] { 0 }; var thread = new ThreadAnonymousInnerClassHelper(this, abPath, abOrd, abYoungChildBase1, abYoungChildBase2, retry, tr, stop, error, retrieval); thread.Start(); indexDir.SleepMillis = 1; // some delay for refresh var newTaxoReader = TaxonomyReader.OpenIfChanged(tr); if (newTaxoReader != null) { newTaxoReader.Dispose(); } stop.Set(true); thread.Join(); Assert.Null(error[0], "Unexpcted exception at retry " + retry + " retrieval " + retrieval[0] + ": \n" + stackTraceStr(error[0])); tr.Dispose(); }
public virtual void TestSeparateReaderAndWriter() { var indexDir = NewDirectory(); var tw = new DirectoryTaxonomyWriter(indexDir); tw.Commit(); var tr = new DirectoryTaxonomyReader(indexDir); Assert.AreEqual(1, tr.Count); // the empty taxonomy has size 1 (the root) tw.AddCategory(new FacetLabel("Author")); Assert.AreEqual(1, tr.Count); // still root only... Assert.Null(TaxonomyReader.OpenIfChanged(tr)); // this is not enough, because tw.Commit() hasn't been done yet Assert.AreEqual(1, tr.Count); // still root only... tw.Commit(); Assert.AreEqual(1, tr.Count); // still root only... var newTaxoReader = TaxonomyReader.OpenIfChanged(tr); Assert.NotNull(newTaxoReader); tr.Dispose(); tr = newTaxoReader; int author = 1; try { Assert.AreEqual(TaxonomyReader.ROOT_ORDINAL, tr.ParallelTaxonomyArrays.Parents[author]); // ok } catch (System.IndexOutOfRangeException) { Fail("After category addition, commit() and refresh(), getParent for " + author + " should NOT throw exception"); } Assert.AreEqual(2, tr.Count); // finally, see there are two categories // now, add another category, and verify that after commit and refresh // the parent of this category is correct (this requires the reader // to correctly update its prefetched parent vector), and that the // old information also wasn't ruined: tw.AddCategory(new FacetLabel("Author", "Richard Dawkins")); int dawkins = 2; tw.Commit(); newTaxoReader = TaxonomyReader.OpenIfChanged(tr); Assert.NotNull(newTaxoReader); tr.Dispose(); tr = newTaxoReader; int[] parents = tr.ParallelTaxonomyArrays.Parents; Assert.AreEqual(author, parents[dawkins]); Assert.AreEqual(TaxonomyReader.ROOT_ORDINAL, parents[author]); Assert.AreEqual(TaxonomyReader.INVALID_ORDINAL, parents[TaxonomyReader.ROOT_ORDINAL]); Assert.AreEqual(3, tr.Count); tw.Dispose(); tr.Dispose(); indexDir.Dispose(); }
public virtual void TestChildrenArraysGrowth() { var indexDir = NewDirectory(); var tw = new DirectoryTaxonomyWriter(indexDir); tw.AddCategory(new FacetLabel("hi", "there")); tw.Commit(); var tr = new DirectoryTaxonomyReader(indexDir); ParallelTaxonomyArrays ca = tr.ParallelTaxonomyArrays; Assert.AreEqual(3, tr.Count); Assert.AreEqual(3, ca.Siblings.Length); Assert.AreEqual(3, ca.Children.Length); Assert.True(Arrays.Equals(new int[] { 1, 2, -1 }, ca.Children)); Assert.True(Arrays.Equals(new int[] { -1, -1, -1 }, ca.Siblings)); tw.AddCategory(new FacetLabel("hi", "ho")); tw.AddCategory(new FacetLabel("hello")); tw.Commit(); // Before refresh, nothing changed.. ParallelTaxonomyArrays newca = tr.ParallelTaxonomyArrays; Assert.AreSame(newca, ca); // we got exactly the same object Assert.AreEqual(3, tr.Count); Assert.AreEqual(3, ca.Siblings.Length); Assert.AreEqual(3, ca.Children.Length); // After the refresh, things change: var newtr = TaxonomyReader.OpenIfChanged(tr); Assert.NotNull(newtr); tr.Dispose(); tr = newtr; ca = tr.ParallelTaxonomyArrays; Assert.AreEqual(5, tr.Count); Assert.AreEqual(5, ca.Siblings.Length); Assert.AreEqual(5, ca.Children.Length); Assert.True(Arrays.Equals(new int[] { 4, 3, -1, -1, -1 }, ca.Children)); Assert.True(Arrays.Equals(new int[] { -1, -1, -1, 2, 1 }, ca.Siblings)); tw.Dispose(); tr.Dispose(); indexDir.Dispose(); }
public virtual void TestTaxonomyReaderRefreshRaces() { // compute base child arrays - after first chunk, and after the other var indexDirBase = NewDirectory(); var twBase = new DirectoryTaxonomyWriter(indexDirBase); twBase.AddCategory(new FacetLabel("a", "0")); FacetLabel abPath = new FacetLabel("a", "b"); twBase.AddCategory(abPath); twBase.Commit(); var trBase = new DirectoryTaxonomyReader(indexDirBase); ParallelTaxonomyArrays ca1 = trBase.ParallelTaxonomyArrays; int abOrd = trBase.GetOrdinal(abPath); int abYoungChildBase1 = ca1.Children[abOrd]; int numCategories = AtLeast(800); for (int i = 0; i < numCategories; i++) { twBase.AddCategory(new FacetLabel("a", "b", Convert.ToString(i))); } twBase.Dispose(); var newTaxoReader = TaxonomyReader.OpenIfChanged(trBase); Assert.NotNull(newTaxoReader); trBase.Dispose(); trBase = newTaxoReader; ParallelTaxonomyArrays ca2 = trBase.ParallelTaxonomyArrays; int abYoungChildBase2 = ca2.Children[abOrd]; int numRetries = AtLeast(50); for (int retry = 0; retry < numRetries; retry++) { AssertConsistentYoungestChild(abPath, abOrd, abYoungChildBase1, abYoungChildBase2, retry, numCategories); } trBase.Dispose(); indexDirBase.Dispose(); }
public virtual void TestChildrenArrays() { var indexDir = NewDirectory(); var tw = new DirectoryTaxonomyWriter(indexDir); FillTaxonomy(tw); tw.Dispose(); var tr = new DirectoryTaxonomyReader(indexDir); ParallelTaxonomyArrays ca = tr.ParallelTaxonomyArrays; int[] youngestChildArray = ca.Children; Assert.AreEqual(tr.Count, youngestChildArray.Length); int[] olderSiblingArray = ca.Siblings; Assert.AreEqual(tr.Count, olderSiblingArray.Length); for (int i = 0; i < ExpectedCategories.Length; i++) { // find expected children by looking at all expectedCategories // for children List<int?> expectedChildren = new List<int?>(); for (int j = ExpectedCategories.Length - 1; j >= 0; j--) { if (ExpectedCategories[j].Length != ExpectedCategories[i].Length + 1) { continue; // not longer by 1, so can't be a child } bool ischild = true; for (int k = 0; k < ExpectedCategories[i].Length; k++) { if (!ExpectedCategories[j][k].Equals(ExpectedCategories[i][k])) { ischild = false; break; } } if (ischild) { expectedChildren.Add(j); } } // check that children and expectedChildren are the same, with the // correct reverse (youngest to oldest) order: if (expectedChildren.Count == 0) { Assert.AreEqual(TaxonomyReader.INVALID_ORDINAL, youngestChildArray[i]); } else { int child = youngestChildArray[i]; Assert.AreEqual((int)expectedChildren[0], child); for (int j = 1; j < expectedChildren.Count; j++) { child = olderSiblingArray[child]; Assert.AreEqual((int)expectedChildren[j], child); // if child is INVALID_ORDINAL we should stop, but // AssertEquals would fail in this case anyway. } // When we're done comparing, olderSiblingArray should now point // to INVALID_ORDINAL, saying there are no more children. If it // doesn't, we found too many children... Assert.AreEqual(-1, olderSiblingArray[child]); } } tr.Dispose(); indexDir.Dispose(); }
public virtual void TestChildrenArraysInvariants() { var indexDir = NewDirectory(); var tw = new DirectoryTaxonomyWriter(indexDir); FillTaxonomy(tw); tw.Dispose(); var tr = new DirectoryTaxonomyReader(indexDir); ParallelTaxonomyArrays ca = tr.ParallelTaxonomyArrays; int[] children = ca.Children; Assert.AreEqual(tr.Count, children.Length); int[] olderSiblingArray = ca.Siblings; Assert.AreEqual(tr.Count, olderSiblingArray.Length); // test that the "youngest child" of every category is indeed a child: int[] parents = tr.ParallelTaxonomyArrays.Parents; for (int i = 0; i < tr.Count; i++) { int youngestChild = children[i]; if (youngestChild != TaxonomyReader.INVALID_ORDINAL) { Assert.AreEqual(i, parents[youngestChild]); } } // test that the "older sibling" of every category is indeed older (lower) // (it can also be INVALID_ORDINAL, which is lower than any ordinal) for (int i = 0; i < tr.Count; i++) { Assert.True(olderSiblingArray[i] < i, "olderSiblingArray[" + i + "] should be <" + i); } // test that the "older sibling" of every category is indeed a sibling // (they share the same parent) for (int i = 0; i < tr.Count; i++) { int sibling = olderSiblingArray[i]; if (sibling == TaxonomyReader.INVALID_ORDINAL) { continue; } Assert.AreEqual(parents[i], parents[sibling]); } // And now for slightly more complex (and less "invariant-like"...) // tests: // test that the "youngest child" is indeed the youngest (so we don't // miss the first children in the chain) for (int i = 0; i < tr.Count; i++) { // Find the really youngest child: int j; for (j = tr.Count - 1; j > i; j--) { if (parents[j] == i) { break; // found youngest child } } if (j == i) // no child found { j = TaxonomyReader.INVALID_ORDINAL; } Assert.AreEqual(j, children[i]); } // test that the "older sibling" is indeed the least oldest one - and // not a too old one or -1 (so we didn't miss some children in the // middle or the end of the chain). for (int i = 0; i < tr.Count; i++) { // Find the youngest older sibling: int j; for (j = i - 1; j >= 0; j--) { if (parents[j] == parents[i]) { break; // found youngest older sibling } } if (j < 0) // no sibling found { j = TaxonomyReader.INVALID_ORDINAL; } Assert.AreEqual(j, olderSiblingArray[i]); } tr.Dispose(); indexDir.Dispose(); }
public virtual void TestReaderParent() { var indexDir = NewDirectory(); var tw = new DirectoryTaxonomyWriter(indexDir); FillTaxonomy(tw); tw.Dispose(); var tr = new DirectoryTaxonomyReader(indexDir); // check that the parent of the root ordinal is the invalid ordinal: int[] parents = tr.ParallelTaxonomyArrays.Parents; Assert.AreEqual(TaxonomyReader.INVALID_ORDINAL, parents[0]); // check parent of non-root ordinals: for (int ordinal = 1; ordinal < tr.Count; ordinal++) { FacetLabel me = tr.GetPath(ordinal); int parentOrdinal = parents[ordinal]; FacetLabel parent = tr.GetPath(parentOrdinal); if (parent == null) { Fail("Parent of " + ordinal + " is " + parentOrdinal + ", but this is not a valid category."); } // verify that the parent is indeed my parent, according to the strings if (!me.Subpath(me.Length - 1).Equals(parent)) { Fail("Got parent " + parentOrdinal + " for ordinal " + ordinal + " but categories are " + Showcat(parent) + " and " + Showcat(me) + " respectively."); } } tr.Dispose(); indexDir.Dispose(); }
public virtual void TestReaderBasic() { var indexDir = NewDirectory(); var tw = new DirectoryTaxonomyWriter(indexDir); FillTaxonomy(tw); tw.Dispose(); var tr = new DirectoryTaxonomyReader(indexDir); // test TaxonomyReader.getSize(): Assert.AreEqual(ExpectedCategories.Length, tr.Count); // test round trips of ordinal => category => ordinal for (int i = 0; i < tr.Count; i++) { Assert.AreEqual(i, tr.GetOrdinal(tr.GetPath(i))); } // test TaxonomyReader.getCategory(): for (int i = 1; i < tr.Count; i++) { FacetLabel expectedCategory = new FacetLabel(ExpectedCategories[i]); FacetLabel category = tr.GetPath(i); if (!expectedCategory.Equals(category)) { Fail("For ordinal " + i + " expected category " + Showcat(expectedCategory) + ", but got " + Showcat(category)); } } // (also test invalid ordinals:) Assert.Null(tr.GetPath(-1)); Assert.Null(tr.GetPath(tr.Count)); Assert.Null(tr.GetPath(TaxonomyReader.INVALID_ORDINAL)); // test TaxonomyReader.GetOrdinal(): for (int i = 1; i < ExpectedCategories.Length; i++) { int expectedOrdinal = i; int ordinal = tr.GetOrdinal(new FacetLabel(ExpectedCategories[i])); if (expectedOrdinal != ordinal) { Fail("For category " + Showcat(ExpectedCategories[i]) + " expected ordinal " + expectedOrdinal + ", but got " + ordinal); } } // (also test invalid categories:) Assert.AreEqual(TaxonomyReader.INVALID_ORDINAL, tr.GetOrdinal(new FacetLabel("non-existant"))); Assert.AreEqual(TaxonomyReader.INVALID_ORDINAL, tr.GetOrdinal(new FacetLabel("Author", "Jules Verne"))); tr.Dispose(); indexDir.Dispose(); }
public virtual void TestRootOnly2() { var indexDir = NewDirectory(); var tw = new DirectoryTaxonomyWriter(indexDir); tw.Commit(); var tr = new DirectoryTaxonomyReader(indexDir); Assert.AreEqual(1, tr.Count); Assert.AreEqual(0, tr.GetPath(0).Length); Assert.AreEqual(TaxonomyReader.INVALID_ORDINAL, tr.ParallelTaxonomyArrays.Parents[0]); Assert.AreEqual(0, tr.GetOrdinal(new FacetLabel())); tw.Dispose(); tr.Dispose(true); indexDir.Dispose(); }
public virtual void TestRootOnly() { var indexDir = NewDirectory(); var tw = new DirectoryTaxonomyWriter(indexDir); // right after opening the index, it should already contain the // root, so have size 1: Assert.AreEqual(1, tw.Count); tw.Dispose(); var tr = new DirectoryTaxonomyReader(indexDir); Assert.AreEqual(1, tr.Count); Assert.AreEqual(0, tr.GetPath(0).Length); Assert.AreEqual(TaxonomyReader.INVALID_ORDINAL, tr.ParallelTaxonomyArrays.Parents[0]); Assert.AreEqual(0, tr.GetOrdinal(new FacetLabel())); tr.Dispose(true); indexDir.Dispose(); }
public virtual void TestNrt() { var dir = NewDirectory(); var writer = new DirectoryTaxonomyWriter(dir); var reader = new DirectoryTaxonomyReader(writer); FacetLabel cp = new FacetLabel("a"); writer.AddCategory(cp); var newReader = TaxonomyReader.OpenIfChanged(reader); Assert.NotNull(newReader, "expected a new instance"); Assert.AreEqual(2, newReader.Count); Assert.AreNotSame(TaxonomyReader.INVALID_ORDINAL, newReader.GetOrdinal(cp)); reader.Dispose(); reader = newReader; writer.Dispose(); reader.Dispose(); dir.Dispose(); }
public virtual void TestWriterLock() { // native fslock impl gets angry if we use it, so use RAMDirectory explicitly. var indexDir = new RAMDirectory(); var tw = new DirectoryTaxonomyWriter(indexDir); tw.AddCategory(new FacetLabel("hi", "there")); tw.Commit(); // we deliberately not close the write now, and keep it open and // locked. // Verify that the writer worked: var tr = new DirectoryTaxonomyReader(indexDir); Assert.AreEqual(2, tr.GetOrdinal(new FacetLabel("hi", "there"))); // Try to open a second writer, with the first one locking the directory. // We expect to get a LockObtainFailedException. try { Assert.Null(new DirectoryTaxonomyWriter(indexDir)); Fail("should have failed to write in locked directory"); } catch (LockObtainFailedException) { // this is what we expect to happen. } // Remove the lock, and now the open should succeed, and we can // write to the new writer. DirectoryTaxonomyWriter.Unlock(indexDir); var tw2 = new DirectoryTaxonomyWriter(indexDir); tw2.AddCategory(new FacetLabel("hey")); tw2.Dispose(); // See that the writer indeed wrote: var newtr = TaxonomyReader.OpenIfChanged(tr); Assert.NotNull(newtr); tr.Dispose(); tr = newtr; Assert.AreEqual(3, tr.GetOrdinal(new FacetLabel("hey"))); tr.Dispose(); tw.Dispose(); indexDir.Dispose(); }