弹性搜索父子数据搜索Java API

时间:2015-03-18 08:11:33

标签: java search elasticsearch java-api

我是ELastic Search的新手。

弹性搜索中的数据位于父子模型中。我想使用java api在此数据中执行搜索。

父类型包含作者详细信息,子类型包含书籍详细信息,如书名,图书出版商,图书类别。

在对子详细信息执行搜索时,我还需要获取父详细信息,反之亦然。有时搜索条件将是父类型和子类型。例如,搜索由author1撰写的书籍并输入Fiction

我如何在java中实现这个?我已经提到了弹性搜索文档,但无法获得解决方案

请帮忙

3 个答案:

答案 0 :(得分:6)

首先使用parent/child映射设置索引。在下面的映射中,我还为categories添加了一个未加密的字段,以便您可以对该字段执行过滤查询。 (对于创建索引和文档,我使用的是JSON API而不是Java API,因为这不是问题的一部分。)

POST /test
{
    "mappings": {
        "book": {
            "_parent": {
                "type": "author"
            },
            "properties":{
                "category":{
                    "type":"string",
                    "fields":{
                        "raw":{
                            "type":"string",
                            "index": "not_analyzed"
                        }
                    }
                }
            }
        }
    }
}

创建一些author文档:

POST /test/author/1
{
    "name": "jon doe"
}


POST /test/author/2
{
    "name": "jane smith"
}

创建一些book文档,指定请求中bookauthor之间的关系。

POST /test/book/12?parent=1
{
    "name": "fictional book",
    "category": "Fiction",
    "publisher": "publisher1"
}

POST /test/book/16?parent=2
{
    "name": "book of history",
    "category": "historical",
    "publisher": "publisher2"
}

POST /test/book/20?parent=2
{
    "name": "second fictional book",
    "category": "Fiction",
    "publisher": "publisher2"
}

下面的Java类执行3个查询:

  1. 搜索标题中包含“book”字词的所有books 返回authors
  2. 搜索名称中包含“jon doe”字词的所有authors 返回books
  3. 搜索“jane smith”撰写的books,其类型为Fiction。
  4. 您可以从命令行运行该类,或导入Eclipse并右键单击该类并选择“Run As> Java应用程序'。 (您需要在类路径中使用Elasticsearch库。)

    import java.util.concurrent.ExecutionException;
    
    import org.elasticsearch.action.search.SearchRequestBuilder;
    import org.elasticsearch.action.search.SearchResponse;
    import org.elasticsearch.client.Client;
    import org.elasticsearch.client.transport.TransportClient;
    import org.elasticsearch.common.settings.ImmutableSettings;
    import org.elasticsearch.common.settings.Settings;
    import org.elasticsearch.common.transport.InetSocketTransportAddress;
    import org.elasticsearch.index.query.FilterBuilders;
    import org.elasticsearch.index.query.HasChildQueryBuilder;
    import org.elasticsearch.index.query.HasParentQueryBuilder;
    import org.elasticsearch.index.query.QueryBuilders;
    import org.elasticsearch.index.query.TermFilterBuilder;
    
    public class ParentChildQueryExample {
    
      public static void main(String args[]) throws InterruptedException, ExecutionException {
    
        //Set the Transport client which is used to communicate with your ES cluster. It is also possible to set this up using the Client Node.
        Settings settings = ImmutableSettings.settingsBuilder()
            .put("cluster.name", "elasticsearch").build();
        Client client = new TransportClient(settings)
            .addTransportAddress(new InetSocketTransportAddress(
            "localhost",
            9300));
    
        //create the searchRequestBuilder object.
        SearchRequestBuilder searchRequestBuilder = new SearchRequestBuilder(client).setIndices("test");
    
        //Query 1. Search on all books that have the term 'book' in the title and return the 'authors'.
        HasChildQueryBuilder bookNameQuery = QueryBuilders.hasChildQuery("book", QueryBuilders.matchQuery("name", "book"));
        System.out.println("Exectuing Query 1");
        SearchResponse searchResponse1 = searchRequestBuilder.setQuery(bookNameQuery).execute().actionGet();
        System.out.println("There were " + searchResponse1.getHits().getTotalHits()  + " results found for Query 1.");
        System.out.println(searchResponse1.toString());
        System.out.println();
    
        //Query 2. Search on all authors that have the terms 'jon doe' in the name and return the 'books'.
        HasParentQueryBuilder authorNameQuery = QueryBuilders.hasParentQuery("author", QueryBuilders.matchQuery("name", "jon doe"));
        System.out.println("Exectuing Query 2");
        SearchResponse searchResponse2 = searchRequestBuilder.setQuery(authorNameQuery).execute().actionGet();
        System.out.println("There were " + searchResponse2.getHits().getTotalHits()  + " results found for Query 2.");
        System.out.println(searchResponse2.toString());
        System.out.println();
    
        //Query 3. Search for books written by 'jane smith' and type Fiction.
        TermFilterBuilder termFilter = FilterBuilders.termFilter("category.raw", "Fiction");
        HasParentQueryBuilder authorNameQuery2 = QueryBuilders.hasParentQuery("author", QueryBuilders.matchQuery("name", "jane smith"));
        SearchResponse searchResponse3 = searchRequestBuilder.setQuery(QueryBuilders.filteredQuery(authorNameQuery2, termFilter)).execute().actionGet();
        System.out.println("There were " + searchResponse3.getHits().getTotalHits()  + " results found for Query 3.");
        System.out.println(searchResponse3.toString());
        System.out.println();
      }
    }
    

答案 1 :(得分:0)

您可以使用Parent-Child documents

让我们创建一个索引bookstore,其中包含作者文档和书籍文档的简单映射。您可以根据自己的要求添加更多字段。有关索引父/子文档的详细信息,请参阅this

PUT bookstore
{
   "mappings": {
      "author": {
         "properties": {
            "authorname": {
               "type": "string"
            }
         }
      },
      "book": {
         "_parent": {
            "type": "author"
         },
         "properties": {
            "bookname": {
               "type": "string"
            }
         }
      }
   }
}

现在让我们添加两位作者:

PUT bookstore/author/1
{
   "authorname": "author1"
}

PUT bookstore/author/2
{
   "authorname": "author2"
}

现在让我们添加两本作者author1的书:

PUT bookstore/book/11?parent=1
{
   "bookname": "book11"
}

PUT bookstore/book/12?parent=1
{
   "bookname": "book12"
}

现在让我们添加两本作者author2的书:

PUT bookstore/book/21?parent=2
{
   "bookname": "book21"
}

PUT bookstore/book/22?parent=2
{
   "bookname": "book22"
}

我们已完成索引文档。现在让我们开始搜索。

搜索作者author1撰写的所有图书(了解详情here

POST bookstore/book/_search
{
   "query": {
      "has_parent": {
         "type": "author",
         "query": {
            "term": {
               "authorname": "author1"
            }
         }
      }
   }
}

搜索图书book11的作者(详细了解此here

POST bookstore/author/_search
{
   "query": {
      "has_child": {
         "type": "book",
         "query": {
            "term": {
               "bookname": "book11"
            }
         }
      }
   }
}

搜索名为book12并由author1创作的图书。您需要使用bool queries来实现此目的。 (对于此方案,可以有更好的示例,文档中包含更多字段)

POST bookstore/book/_search
{
   "query": {
      "bool": {
         "must": [
            {
               "has_parent": {
                  "type": "author",
                  "query": {
                     "term": {
                        "authorname": "author1"
                     }
                  }
               }
            },
            {
               "term": {
                  "bookname": {
                     "value": "book12"
                  }
               }
            }
         ]
      }
   }
}

答案 2 :(得分:0)

我用“spring-data-elasticsearch”库做了类似的事情。他们的测试套件上有大量样品可供使用。

点击git上的这个链接:https://github.com/spring-projects/spring-data-elasticsearch/blob/master/src/test/java/org/springframework/data/elasticsearch/NestedObjectTests.java

    List<Car> cars = new ArrayList<Car>();

    Car saturn = new Car();
    saturn.setName("Saturn");
    saturn.setModel("SL");

    Car subaru = new Car();
    subaru.setName("Subaru");
    subaru.setModel("Imprezza");

    Car ford = new Car();
    ford.setName("Ford");
    ford.setModel("Focus");

    cars.add(saturn);
    cars.add(subaru);
    cars.add(ford);

    Person foo = new Person();
    foo.setName("Foo");
    foo.setId("1");
    foo.setCar(cars);


    Car car  = new Car();
    car.setName("Saturn");
    car.setModel("Imprezza");

    Person bar = new Person();
    bar.setId("2");
    bar.setName("Bar");
    bar.setCar(Arrays.asList(car));

    List<IndexQuery> indexQueries = new ArrayList<IndexQuery>();
    IndexQuery indexQuery1 = new IndexQuery();
    indexQuery1.setId(foo.getId());
    indexQuery1.setObject(foo);

    IndexQuery indexQuery2 = new IndexQuery();
    indexQuery2.setId(bar.getId());
    indexQuery2.setObject(bar);

    indexQueries.add(indexQuery1);
    indexQueries.add(indexQuery2);

    elasticsearchTemplate.putMapping(Person.class);
    elasticsearchTemplate.bulkIndex(indexQueries);
    elasticsearchTemplate.refresh(Person.class, true);

    SearchQuery searchQuery = new NativeSearchQueryBuilder().build();
    List<Person> persons = elasticsearchTemplate.queryForList(searchQuery, Person.class);