Elasticsearch不应用NOT过滤器

时间:2023-02-01 03:07:10

I've been knocking my head against a wall with Elasticsearch today, trying to fix a failing test case.

今天我一直在用Elasticsearch撞墙,试图修复一个失败的测试用例。

I am using Rails 3.2.14, Ruby 1.9.3, the Tire gem and ElasticSearch 0.90.2

我使用的是Rails 3.2.14,Ruby 1.9.3,Tire gem和ElasticSearch 0.90.2

The objective is to have the query return matching results EXCLUDING the item where vid == "ABC123xyz"

目标是让查询返回匹配结果排除vid ==“ABC123xyz”的项目

The Ruby code in the Video model looks like this:

Video模型中的Ruby代码如下所示:

def related_videos(count)
  Video.search load: true do
    size(count)
    filter :term, :category_id => self.category_id
    filter :term, :live => true
    filter :term, :public => true
    filter :not, {:term => {:vid => self.vid}}
    query do
      boolean do
        should { text(:_all, self.title, boost: 2) }
        should { text(:_all, self.description) }
        should { terms(:tags, self.tag_list, minimum_match: 1) }
      end  
   end
  end
end

The resulting search query generated by Tire looks like this:

由Tire生成的搜索查询结果如下所示:

{
  "query":{
    "bool":{
      "should":[
        {
          "text":{
            "_all":{
              "query":"Top Gun","boost":2
            }
          }
        },
        {
          "text":{
            "_all":{
              "query":"The macho students of an elite US Flying school for advanced fighter pilots compete to be best in the class, and one romances the teacher."
            }
          }
        },
        {
          "terms":{
            "tags":["top-gun","80s"],
            "minimum_match":1
          }
        }
      ]
    }
  },
  "filter":{
    "and":[
      {
        "term":{
          "category_id":1
        }
      },
      {
        "term":{
          "live":true
        }
      },
      {
        "term":{
          "public":true
        }
      },
      {
        "not":{
          "term":{
            "vid":"ABC123xyz"
          }
        }
      }
    ]
  },
  "size":10
}

The resulting JSON from ElasticSearch:

ElasticSearch生成的JSON:

{
  "took": 7,
  "timed_out": false,
  "_shards":{
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total":1,
    "max_score":0.2667512,
    "hits":[
      {
        "_index":"test_videos",
        "_type":"video",
        "_id":"8",
        "_score":0.2667512,
        "_source":{
          "vid":"ABC123xyz",
          "title":"Top Gun",
          "description":"The macho students of an elite US Flying school for advanced fighter pilots compete to be best in the class, and one romances the teacher.",
          "tags":["top-gun","80s"],
          "category_id":1,
          "live":true,
          "public":true,
          "featured":false,
          "last_video_view_count":0,
          "boost_factor":0.583013698630137,
          "created_at":"2013-08-28T14:24:47Z"
        }
      }
    ]
  }
}

Could somebody help! The docs for Elasticsearch are sparse around this topic and I'm running out of ideas.

有人可以帮忙! Elasticsearch的文档围绕这个主题很少,而且我的想法已经不多了。

Thanks

1 个解决方案

#1


0  

Using a top-level filter the way you are doesn't filter the results of your query - it just filters results out of things like facet counts. There's a fuller description in the elasticsearch documentation for filter.

使用*过滤器的方式不会过滤查询结果 - 它只会过滤结果计数等结果。过滤器的elasticsearch文档中有更全面的描述。

You need to do a filtered query which is slightly different and filters the results of your query clauses:

您需要执行略有不同的筛选查询,并过滤查询子句的结果:

Video.search load: true do
  query do
    filtered do
      boolean do
        should { text(:_all, self.title, boost: 2) }
        should { text(:_all, self.description) }
        should { terms(:tags, self.tag_list, minimum_match: 1) }
      end  
      filter :term, :category_id => self.category_id
      filter :term, :live => true
      filter :term, :public => true
      filter :not, {:term => {:vid => self.vid}}
    end
  end
end

#1


0  

Using a top-level filter the way you are doesn't filter the results of your query - it just filters results out of things like facet counts. There's a fuller description in the elasticsearch documentation for filter.

使用*过滤器的方式不会过滤查询结果 - 它只会过滤结果计数等结果。过滤器的elasticsearch文档中有更全面的描述。

You need to do a filtered query which is slightly different and filters the results of your query clauses:

您需要执行略有不同的筛选查询,并过滤查询子句的结果:

Video.search load: true do
  query do
    filtered do
      boolean do
        should { text(:_all, self.title, boost: 2) }
        should { text(:_all, self.description) }
        should { terms(:tags, self.tag_list, minimum_match: 1) }
      end  
      filter :term, :category_id => self.category_id
      filter :term, :live => true
      filter :term, :public => true
      filter :not, {:term => {:vid => self.vid}}
    end
  end
end