索引/搜索elasticsearch中的"复杂"JSON

sca*_*ble 10 python django json django-haystack elasticsearch

我有一些看起来如下的JSON:让我们调用该字段元数据

{ 
  "somekey1": "val1",
  "someotherkey2": "val2",
  "more_data": { 
    "contains_more": [
      { 
        "foo": "val5",
        "bar": "val6"
      },
      { 
        "foo": "val66",
        "baz": "val44"
      },
    ],
    "even_more": {
      "foz" : 1234,
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

这只是一个简单的例子.真正的人可以变得更加复杂.钥匙可以多次出现.值也可以是int或str.

现在第一个问题是我不太确定如何在elasticsearch中对此进行正确索引,以便我可以找到具有特定请求的内容.

我正在使用Django/Haystack,索引如下所示:

class FooIndex(indexes.SearchIndex, indexes.Indexable):
    text = indexes.CharField(document=True, use_template=True)
    metadata = indexes.CharField(model_attr='get_metadata')
    # and some more specific fields
Run Code Online (Sandbox Code Playgroud)

和模板:

{
    "foo": {{ object.foo }},
    "metadata": {{ object.metadata}},
    # and some more
}
Run Code Online (Sandbox Code Playgroud)

然后将使用上面的示例填充元数据,结果将如下所示:

  {
    "foo": "someValue",
    "metadata": { 
      "somekey1": "val1",
      "someotherkey2": "val2",
      "more_data": { 
        "contains_more": [
          { 
            "foo": "val5",
            "bar": "val6"
          },
          { 
            "foo": "val66",
            "baz": "val44"
          },
        ],
        "even_more": {
          "foz" : 1234,
        }
      }
    },
  }
Run Code Online (Sandbox Code Playgroud)

这将进入elasticsearch的'text'列.

因此,现在的目标是能够搜索以下内容:

  • foo:val5
  • 福兹:12*
  • bar:val*
  • somekey1:val1
  • 等等

第二个问题:当我搜索例如foo:val5时,它匹配所有具有键"foo"的对象以及在其结构中具有val5的所有对象.

这是我在Django中搜索的方式:

self.searchqueryset.auto_query(self.cleaned_data['q'])
Run Code Online (Sandbox Code Playgroud)

有时结果是"好的",有时它完全没用.

我可能需要一个正确方向的指针,并了解我在这里犯的错误.谢谢!

编辑:我在下面添加了我的最终解决方案作为答案!

sca*_*ble 0

我花了一段时间才找到适合我的正确解决方案

它混合了@juliendangers@Val提供的答案以及一些更多的自定义内容。

  1. 我用更具体的django-simple-elasticsearch替换了 Haystack
  2. get_type_mapping向模型添加自定义方法

    @classmethod
    def get_type_mapping(cls):
      return {
        "properties": {
          "somekey": {
            "type": "<specific_type>",
            "format": "<specific_format>",
          },
          "more_data": {
            "type": "nested",
            "include_in_parent": True,
            "properties": {
              "even_more": {
                "type": "nested",
                "include_in_parent": True,
              }
              /* and so on for each level you care about */
           }
         }
      }
    
    Run Code Online (Sandbox Code Playgroud)
  3. get_document向模型添加自定义方法

    @classmethod
    def get_document(cls, obj):
      return {
        'somekey': obj.somekey,
        'more_data': obj.more_data,
        /* and so on */
      }
    
    Run Code Online (Sandbox Code Playgroud)
  4. 添加自定义搜索表单

    class Searchform(ElasticsearchForm):
      q = forms.Charfield(required=False)
    
      def get_index(self):
        return 'your_index'
    
      def get_type(self):
        return 'your_model'
    
      def prepare_query(self):
        if not self.cleaned_data['q']:
          q = "*"
        else:
          q = str(self.cleaned_data['q'])
    
        return {
          "query": {
            "query_string": {
              "query": q
            }
          }
        }
    
      def search(self):
        esp = ElasticsearchProcessor(self.es)
        esp.add_search(self.prepare_query, page=1, page_size=25, index=self.get_index(), doc_type=self.get_type())
        responses = esp.search()
        return responses[0]
    
    Run Code Online (Sandbox Code Playgroud)

所以这对我有用并涵盖了我的用例。也许这对某人有帮助。