如何使用Elastica Search和Symfony2执行嵌套查询

时间:2014-06-24 09:42:41

标签: symfony elasticsearch mapping nested-queries

我有一个配方实体,它有一些标签(多对多映射),我想按标签搜索食谱。

这是我的食谱实体:

/**
 * @ORM\Entity
 * @ORM\Table(name="recipes")
 * @ORM\HasLifecycleCallbacks
 * @ExclusionPolicy("all")
 */
class Recipe
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     * @Expose
     */
    protected $id;

    /**
     * @ORM\Column(type="string", length=150)
     * @Expose
     */
    protected $name;

    ...

    /**
     * @ORM\ManyToMany(targetEntity="RecipesTag", inversedBy="recipes")
     * @ORM\JoinTable(name="bind_recipes_tags",
     *      joinColumns={@ORM\JoinColumn(name="tag_id", referencedColumnName="id")},
     *      inverseJoinColumns={@ORM\JoinColumn(name="recipe_id", referencedColumnName="id")}
     *      )
     */
    private $tags;

这是我的配置:

fos_elastica:
    clients:
        default: { host: localhost, port: 9200 }
    serializer:
        callback_class: FOS\ElasticaBundle\Serializer\Callback
        serializer: serializer
    indexes:
        td:
            client: default
            types:
                Recipe:
                    mappings:
                        name: ~
                        ingredients: 
                            type: "nested"
                            properties:
                                name: ~
                        tags:
                            type: "nested"
                            properties:
                                name: ~
                                id : 
                                    type : integer
                        categories:
                            type: "nested"
                            properties:
                                name: ~
                                id : 
                                    type : integer

                    persistence:
                        driver: orm # orm, mongodb, propel are available
                        model:  ck\RecipesBundle\Entity\Recipe
                        repository: ck\RecipesBundle\Entity\RecipesRepository
                        provider: ~
                        listener: ~
                        finder: ~

然后我添加了一个自定义存储库来执行搜索:

public function filterFind($searchText)
{
    $query_part = new \Elastica\Query\Bool();

    $nested = new \Elastica\Query\Nested();
    $nested->setQuery(new \Elastica\Query\Term(array('name' => array('value' => $searchText))));
    $nested->setPath('tags');
    $query_part->addShould($nested);

    return $this->find($query_part);
}

然后我这样搜索:

$repositoryManager = $this->get('fos_elastica.manager.orm');
$repository = $repositoryManager->getRepository('ckRecipesBundle:Recipe');

$recipes = $repository->filterFind('mytag');

但是尽管有匹配的结果,但我没有得到任何结果。

我在谷歌上找不到任何答案。 有人可以帮帮我吗?

2 个答案:

答案 0 :(得分:0)

实际上,您忘了定义Filtered查询。

这应该有效:

public class CurrencyConverter extends Fragment {
    public CurrencyConverter() {
    }
    TextView t;
    public int to;
    public int from;
    public String[] val;
    public String s;
    String exResult;
    public Handler handler;


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {


         View rootView = inflater.inflate(R.layout.currency_converter, container, false);
        t= (TextView) rootView.findViewById(R.id.textView4);
        Spinner s1 = (Spinner) rootView.findViewById(R.id.spinner1);
        Spinner s2 = (Spinner) rootView.findViewById(R.id.spinner2);
        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
                this.getActivity(), R.array.name, android.R.layout.simple_spinner_item);
        adapter.setDropDownViewResource(android.R.layout.select_dialog_singlechoice);
        val = getResources().getStringArray(R.array.value);
        s1.setAdapter(adapter);
        s2.setAdapter(adapter);
        s1.setOnItemSelectedListener(new spinOne(1));
        s2.setOnItemSelectedListener(new spinOne(2));

        Button b = (Button) rootView.findViewById(R.id.button1);
        b.setOnClickListener(new View.OnClickListener() {
            public void onClick(View View) {



                if (from == to) {
                    Toast.makeText(getActivity().getApplicationContext(), "Invalid", 4000).show();
                } else {
                    new calculate().execute();

                }
            }

        });
        return rootView;
    }

    public class calculate extends AsyncTask<String, String, String> {
        @Override
        protected void onPreExecute() {
            super.onPreExecute();

        }

        @Override
        protected String doInBackground(String... args) {

            try {

                s = getJson("http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20yahoo.finance.xchange%20where%20pair%20in%20(%22"+val[from]+val[to]+"%22)&format=json&diagnostics=true&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys&callback=");
                JSONObject jObj;
                jObj = new JSONObject(s);
                 exResult = jObj.getJSONObject("query").getJSONObject("results").getJSONObject("rate").getString("Rate");


            } catch (JSONException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (ClientProtocolException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return exResult;

        }
        @Override
        protected void onPostExecute(String exResult) {

           t.setText(exResult);
        }



       }

    public String getJson(String url)throws  IOException {

        StringBuilder build = new StringBuilder();
        HttpClient client = new DefaultHttpClient();
        HttpGet httpGet = new HttpGet(url);
        HttpResponse response = client.execute(httpGet);
        HttpEntity entity = response.getEntity();
        InputStream content = entity.getContent();
        BufferedReader reader = new BufferedReader(new InputStreamReader(content));
        String con;
        while ((con = reader.readLine()) != null) {
            build.append(con);
        }
        return build.toString();
    }

        public class spinOne implements AdapterView.OnItemSelectedListener
        {
            int ide;
            spinOne(int i)
            {
                ide =i;
            }
            public void onItemSelected(AdapterView<?> parent, View view,
                                       int index, long id) {
                if(ide == 1)
                    from = index;
                else if(ide == 2)
                    to = index;

            }

            public void onNothingSelected(AdapterView<?> arg0) {
                // TODO Auto-generated method stub
            }

    }
}

答案 1 :(得分:-1)

以下是响应方法。对我来说它有效。 http://obtao.com/blog/2014/04/elasticsearch-advanced-search-and-nested-objects/

基本上,您需要创建类似的查询:

{
    "query":{
        "filtered":{
            "query":{
                "query_string":{
                    "query":"*saf*"
                }
            },
            "filter":{
                "nested":{
                    "path":"categories",
                    "filter":{
                        "bool":{
                            "must": [{
                                "term":{
                                    "categories.id":1
                                }
                            }]
                        }
                    },
                    "query":{
                        "match":{
                            "id":1
                        }
                    }
                }
            }
        }
    }
} 

对我来说,PHP看起来像:

        $bool = new Filter\Bool();
        $bool->addMust(new Filter\Term(['categories.id' => $category->getId()]));

        $nested = new Filter\Nested();
        $nested->setPath("categories");
        $nested->setFilter($bool);

        $nested->setQuery($categoriesQuery);

        $queryObj = new Query\Filtered($queryObj, $nested);

过滤器是Elastica \ Filter,Query是Elastica \ Query