【问题标题】:How to search in ElasticSearch nested objects using NEST如何使用 NEST 在 ElasticSearch 嵌套对象中进行搜索
【发布时间】:2015-06-23 08:43:30
【问题描述】:

我正在尝试使用 NEST c# 客户端搜索我的 elasticsearch 嵌套对象。 我的索引名称是people,我的类型是person,其中car 字段是nested

这是我的课:

using Nest;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WebApplication5
{
public class person
{
    public int id { get; set; }
    public String fname  { get; set; }
    public String mname { get; set; }
    public String lname { get; set; }
    public String houseno { get; set; }
    [ElasticProperty(Type = FieldType.Nested)]
    public IList<NestedType> car { get; set; } 
    public class NestedType
    {
        public String carname { get; set; }
        public int car_no { get; set; }
        public String color { get; set; }
    }
}

} 

现在我的 Web 应用程序看起来像这样:

using Elasticsearch.Net;
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Configuration;
using Nest;
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace WebApplication5
{
public partial class WebForm1 : System.Web.UI.Page
{
    Stopwatch stopwatch = new Stopwatch();
    Uri node;
    ConnectionSettings settings;
    ElasticClient client;
    IList<person> list;
    protected void Page_Load(object sender, EventArgs e)
    {
        node = new Uri("http://localhost:9200");
        settings = new ConnectionSettings(node, defaultIndex:   "people");
        client = new ElasticClient(settings);
        list = new List<person>();

    }

    public IList<person> Search(ref long totalResult, int from,  int size, string searchKeyword)
    {
        list.Clear();
        stopwatch.Start();

        try
        {

            var result = client.Search<person> /*   */


  stopwatch.Start();
  totalResult = result.Total;
  list = result.Hits.Select(t => t.Source).ToList<person>();
  }
        catch (Exception ex)
        {
            string msg = ex.Message;
        }
 return 
            list;
    }
 protected void TextBox1_TextChanged(object sender, EventArgs e)
    {
        long totalResult = 0;
        IList<person> List = new List<person>();
        List = Search(ref totalResult, 0, 1000,TextBox1.Text);
        Label1.Text = "" + List.Count + " result(s)"+ " in "+ stopwatch.Elapsed.TotalSeconds+"seconds";
        GridView1.DataSource = List;
        GridView1.DataBind();
        List.Clear();

    }
  }
}

这里searchKeyword是我需要搜索的词。
我在浏览器的搜索框(网络表单)中输入它。
searchKeyword 可能包含任何需要与我的表 person 中的任何字段的值匹配的值。
如果 searchKeyword 与嵌套文档匹配,则应返回确切的嵌套文档。
我不知道我的嵌套查询有问题,或者我实际上不知道如何使用嵌套查询来执行此操作。每次我运行应用程序并搜索表中实际存在的值时,我得到的结果为零。请帮助我弄清楚如何编写 query 以在嵌套字段中搜索并帮助我检查我是否正确编写了 class。 查询部分标记为 /* */。 谁能帮我解决这个问题?

更新 这是我的索引映射:

POST- people/person/_mapping
{
"person":{
"properties":{
  "car": {
    "type": "nested"
    }
  }
 }
}

我的记录是这样的:

POST-people/person
{
"id":1, 
"fname":"aditi",  
"mname":"ananya", 
"lname":"xyz", 
"houseno":"abc",
"car":
 [
  {
   "carname":"fiat",
   "carno":1234,
   "color":"white"
  },

  {
   "carname":"maruti",
   "carno":5678,
   "color":"silver"
  }
 ]
}


POST-people/person
{
"id":2, 
"fname":"robin",  
"mname":"kumar", 
"lname":"sharma", 
"houseno":"efg",
"car":
  [
   {
      "carname":"audi",
      "carno":4321,
      "color":"black"
   },

   {
      "carname":"honda",
      "carno":8765,
      "color":"red"
   },

   {
      "carname":"merecedez",
      "carno":0101,
      "color":"purple"
   }
 ]
}

这意味着我有 2 条记录。

第二次更新
我试过这个查询,它工作正常。虽然这不是我的最终查询。

POST-people/person/_search
{
"_source":false,
"query": {
"filtered": {
  "query": {"match_all": {}},
  "filter": {
    "nested": {
      "path": "car",
      "query":{
        "filtered": {
          "query": { "match_all": {}},
          "filter": {
            "and": [
              {"term": {"car.carname":"mercedez"}},
              {"term": {"car.color":"purple"}}
            ]
          }
        }
      },
"inner_hits":{}
    }
  }
 }
}
}

第三次更新
好的,所以现在在这种情况下,我的最终查询应该是:

{"_source":false,
"query": {
 "filtered": {
  "query": {"match_all": {}},
  "filter": {
    "nested": {
      "path": "car",
      "filter": {
        "term": {
          "car.carname": "audi"
        }
      }, 
      "inner_hits" : {}
    }
   }
  }
 }
}

如何在 .net 中编写此查询?
在这里,“_source”和“inner_hits”对我来说很重要,因为我只想返回匹配的嵌套文档而不返回其他任何内容(即我只想返回匹配的嵌套文档而不是其他嵌套文档)。
那么,您能帮我写下相应的搜索查询吗?
此外,我在这里匹配car.carname 字段,但我希望我的应用程序应该能够匹配car 字段的所有其他子字段,例如car.carnocar.color,甚至所有其他子字段idfname 等顶级字段。

第四次更新
在这里,我在 .net 中为我在 第三次更新 中提到的最终查询编写了搜索查询(请查看我的第三次更新)。
你能检查一下是否正确吗? 我写的.net中相应的最终查询是:

(s => s
 .Source(false)
   .Query(query => query.Filtered(filtered => filtered
    .Query(q => q.MatchAll())
      .Filter(f => f.Nested(nf => nf
        .InnerHits()
        .Path(p => p.car)
        .Query(qq => qq.Match(m => m.OnField(g=>g.car.First().carname).Query("audi"))))))));  

这是我通过研究您的查询所写的(非常感谢 :))。请检查一下并告诉我是否有任何问题。但是,是的,我仍然无法检索任何结果。

【问题讨论】:

    标签: c# .net elasticsearch nested nest


    【解决方案1】:

    尝试使用嵌套查询。

    让我为测试目的索引一些数据:

    client.Index(new Person
    {
        Id = 1, 
        Car = new List<NestedType> {new NestedType {Carname = "car1"}}
    });
    client.Index(new Person
    {
        Id = 2,
        Car = new List<NestedType> {new NestedType {Carname = "car1"}, new NestedType {Carname = "car2"}}
    });
    client.Index(new Person
    {
        Id = 3,
        Car = new List<NestedType> { new NestedType {Carname = "car2"}}
    });
    
    client.Refresh();
    

    现在,试试这个嵌套查询:

    var searchResponse = client.Search<Person>(s =>
        s.Query(q => q
            .Nested(n => n
                .Path(p => p.Car)
                .Query(qq => qq.Match(m => m.OnField(f => f.Car.First().Carname).Query("car2"))))));
    

    搜索结果:

    {
       "took": 10,
       "timed_out": false,
       "_shards": {..},
       "hits": {
          "total": 2,
          "max_score": 1.4054651,
          "hits": [
             {
                "_index": "my_index",
                "_type": "person",
                "_id": "2",
                "_score": 1.4054651,
                "_source": {
                   "id": 2,
                   "car": [
                      {
                         "carname": "car1",
                         "carNo": 0
                      },
                      {
                         "carname": "car2",
                         "carNo": 0
                      }
                   ]
                }
             },
             {
                "_index": "my_index",
                "_type": "person",
                "_id": "3",
                "_score": 1,
                "_source": {
                   "id": 3,
                   "car": [
                      {
                         "carname": "car2",
                         "carNo": 0
                      }
                   ]
                }
             }
          ]
       }
    }
    

    希望对你有帮助。

    更新

    包括您的格式:

    var searchResponse = client.Search<person>(s =>
        s.Query(q => q
            .Nested(n => n
                .Path(p => p.car)
                .Query(qq => qq.Match(m => m.OnField(f => f.car.First().carname).Query("car2"))))));
    

    更新2

    根据您的更新,试试这个查询:

    var searchResponse = client.Search<Person>(s => s
        .Query(query => query.Filtered(filtered => filtered
            .Query(q => q.MatchAll())
            .Filter(f => f.Nested(nf => nf
                .Path(p => p.Car)
                .Filter(filter => filter
                    .And(
                        f1 => f1.Term(t => t.Car.First().Carname, "audi"),
                        f2 => f2.Term(t => t.Car.First().Color, "purple"))) 
                )))));
    

    向elasticsearch产生这个查询:

    {
      "query": {
        "filtered": {
          "query": {
            "match_all": {}
          },
          "filter": {
            "nested": {
              "filter": {
                "and": {
                  "filters": [
                    {
                      "term": {
                        "car.carname": "audi"
                      }
                    },
                    {
                      "term": {
                        "car.color": "purple"
                      }
                    }
                  ]
                }
              },
              "path": "car"
            }
          }
        }
      }
    }
    

    更新3

    内部点击:

    var searchResponse = client.Search<Person>(s => s
        .Source(false)
        .Query(query => query.Filtered(filtered => filtered
            .Query(q => q.MatchAll())
            .Filter(f => f.Nested(nf => nf
                .InnerHits()
                .Path(p => p.Car)
                .Filter(filter => filter
                    .And(
                        f1 => f1.Term(t => t.Car.First().Carname, "audi"),
                        f2 => f2.Term(t => t.Car.First().Color, "purple")))
                )))));
    

    注意:elasticsearch 1.5.0 中存在关于内部命中和过滤器的错误。 Have a look. 如果您在检索内部点击方面需要帮助,请告诉我。

    【讨论】:

    • ...非常感谢您的回答。实际上,我的 elasticsearch 数据库中已经有记录,所以,我正在其中进行搜索。但是对于您给出的查询,我分别在第 1、第 2 和第 5 行的 's' 、 'q' 和 'f' 中遇到错误。它分别为“s”、“q”和“f”显示“无法将 lambda 表达式转换为类型 'Nest.ISearchRequest'/'Nest.IQueryContainer'/'string',因为它不是委托类型”。使用first()还有另一个错误。
    • 可能是因为我将属性调整为更多“.Net 方式”。尝试使用你的名字:Car -> car, Carname -> carname 等。
    • 是的,我已经只使用了我的名字。但问题是我现在没有收到任何错误,但是当我运行 Web 应用程序并搜索实际存在于 carname 字段中的值时,我得到的结果为零。我的班级设计有什么问题吗?
    • @AditiAnanya 可以分享索引映射,以及创建索引的代码吗?
    • 请查看我的更新。我已经分享了我的索引映射和我拥有的记录。 :) 是的,我的索引创建和记录插入是通过 elasticsearch head 插件完成的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-03-27
    • 1970-01-01
    • 2011-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-08
    相关资源
    最近更新 更多