    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *     http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017package org.apache.lucene.demo.facet;
    018
    019
    020import java.io.IOException;
    021import java.util.ArrayList;
    022import java.util.List;
    023
    024import org.apache.lucene.analysis.core.WhitespaceAnalyzer;
    025import org.apache.lucene.document.Document;
    026import org.apache.lucene.facet.DrillDownQuery;
    027import org.apache.lucene.facet.FacetResult;
    028import org.apache.lucene.facet.Facets;
    029import org.apache.lucene.facet.FacetsCollector;
    030import org.apache.lucene.facet.FacetsConfig;
    031import org.apache.lucene.facet.taxonomy.FloatAssociationFacetField;
    032import org.apache.lucene.facet.taxonomy.IntAssociationFacetField;
    033import org.apache.lucene.facet.taxonomy.TaxonomyFacetSumFloatAssociations;
    034import org.apache.lucene.facet.taxonomy.TaxonomyFacetSumIntAssociations;
    035import org.apache.lucene.facet.taxonomy.TaxonomyReader;
    036import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyReader;
    037import org.apache.lucene.facet.taxonomy.directory.DirectoryTaxonomyWriter;
    038import org.apache.lucene.index.DirectoryReader;
    039import org.apache.lucene.index.IndexWriter;
    040import org.apache.lucene.index.IndexWriterConfig;
    041import org.apache.lucene.index.IndexWriterConfig.OpenMode;
    042import org.apache.lucene.search.IndexSearcher;
    043import org.apache.lucene.search.MatchAllDocsQuery;
    044import org.apache.lucene.store.Directory;
    045import org.apache.lucene.store.RAMDirectory;
    046
    047/** Shows example usage of category associations. */
    048public class AssociationsFacetsExample {
    049
    050  private final Directory indexDir = new RAMDirectory();
    051  private final Directory taxoDir = new RAMDirectory();
    052  private final FacetsConfig config;
    053
    054  /** Empty constructor */
    055  public AssociationsFacetsExample() {
    056    config = new FacetsConfig();
    057    config.setMultiValued("tags", true);
    058    config.setIndexFieldName("tags", "$tags");
    059    config.setMultiValued("genre", true);
    060    config.setIndexFieldName("genre", "$genre");
    061  }
    062
    063  /** Build the example index. */
    064  private void index() throws IOException {
    065    IndexWriterConfig iwc = new IndexWriterConfig(new WhitespaceAnalyzer()).setOpenMode(OpenMode.CREATE);
    066    IndexWriter indexWriter = new IndexWriter(indexDir, iwc);
    067
    068    // Writes facet ords to a separate directory from the main index
    069    DirectoryTaxonomyWriter taxoWriter = new DirectoryTaxonomyWriter(taxoDir);
    070
    071    Document doc = new Document();
    072    // 3 occurrences for tag 'lucene'
    073    doc.add(new IntAssociationFacetField(3, "tags", "lucene"));
    074    // 87% confidence level of genre 'computing'
    075    doc.add(new FloatAssociationFacetField(0.87f, "genre", "computing"));
    076    indexWriter.addDocument(config.build(taxoWriter, doc));
    077
    078    doc = new Document();
    079    // 1 occurrence for tag 'lucene'
    080    doc.add(new IntAssociationFacetField(1, "tags", "lucene"));
    081    // 2 occurrence for tag 'solr'
    082    doc.add(new IntAssociationFacetField(2, "tags", "solr"));
    083    // 75% confidence level of genre 'computing'
    084    doc.add(new FloatAssociationFacetField(0.75f, "genre", "computing"));
    085    // 34% confidence level of genre 'software'
    086    doc.add(new FloatAssociationFacetField(0.34f, "genre", "software"));
    087    indexWriter.addDocument(config.build(taxoWriter, doc));
    088
    089    indexWriter.close();
    090    taxoWriter.close();
    091  }
    092
    093  /** User runs a query and aggregates facets by summing their association values. */
    094  private List<FacetResult> sumAssociations() throws IOException {
    095    DirectoryReader indexReader = DirectoryReader.open(indexDir);
    096    IndexSearcher searcher = new IndexSearcher(indexReader);
    097    TaxonomyReader taxoReader = new DirectoryTaxonomyReader(taxoDir);
    098
    099    FacetsCollector fc = new FacetsCollector();
    100
    101    // MatchAllDocsQuery is for "browsing" (counts facets
    102    // for all non-deleted docs in the index); normally
    103    // you'd use a "normal" query:
    104    FacetsCollector.search(searcher, new MatchAllDocsQuery(), 10, fc);
    105
    106    Facets tags = new TaxonomyFacetSumIntAssociations("$tags", taxoReader, config, fc);
    107    Facets genre = new TaxonomyFacetSumFloatAssociations("$genre", taxoReader, config, fc);
    108
    109    // Retrieve results
    110    List<FacetResult> results = new ArrayList<>();
    111    results.add(tags.getTopChildren(10, "tags"));
    112    results.add(genre.getTopChildren(10, "genre"));
    113
    114    indexReader.close();
    115    taxoReader.close();
    116
    117    return results;
    118  }
    119
    120  /** User drills down on 'tags/solr'. */
    121  private FacetResult drillDown() throws IOException {
    122    DirectoryReader indexReader = DirectoryReader.open(indexDir);
    123    IndexSearcher searcher = new IndexSearcher(indexReader);
    124    TaxonomyReader taxoReader = new DirectoryTaxonomyReader(taxoDir);
    125
    126    // Passing no baseQuery means we drill down on all
    127    // documents ("browse only"):
    128    DrillDownQuery q = new DrillDownQuery(config);
    129
    130    // Now user drills down on Publish Date/2010:
    131    q.add("tags", "solr");
    132    FacetsCollector fc = new FacetsCollector();
    133    FacetsCollector.search(searcher, q, 10, fc);
    134
    135    // Retrieve results
    136    Facets facets = new TaxonomyFacetSumFloatAssociations("$genre", taxoReader, config, fc);
    137    FacetResult result = facets.getTopChildren(10, "genre");
    138
    139    indexReader.close();
    140    taxoReader.close();
    141
    142    return result;
    143  }
    144
    145  /** Runs summing association example. */
    146  public List<FacetResult> runSumAssociations() throws IOException {
    147    index();
    148    return sumAssociations();
    149  }
    150
    151  /** Runs the drill-down example. */
    152  public FacetResult runDrillDown() throws IOException {
    153    index();
    154    return drillDown();
    155  }
    156
    157  /** Runs the sum int/float associations examples and prints the results. */
    158  public static void main(String[] args) throws Exception {
    159    System.out.println("Sum associations example:");
    160    System.out.println("-------------------------");
    161    List<FacetResult> results = new AssociationsFacetsExample().runSumAssociations();
    162    System.out.println("tags: " + results.get(0));
    163    System.out.println("genre: " + results.get(1));
    164  }
    165}