Indexing and percolating documents with elasticsearch

I'm making and investigation for a seminar in retrieval information. I have a json file with a list of articles and i need to index them and after use a percolator with highlighting.

The list of steps for do this in terminal is this:
1. Create a map with percolating.

curl -XPUT 'localhost:9200/my-index?pretty' -H 'Content-Type: application/json' -d'
{
    "mappings": {
        "_doc": {
            "properties": {
                "title": {
                    "type": "text"
                },
                "query": {
                    "type": "percolator"
                }
            }
        }
    }
}
'
  • Index a new article:

    curl -XPUT 'localhost:9200/my-index/_doc/1?refresh&pretty' -H 'Content-Type: application/json' -d'
    {           
        "CourseId":35,
          "UnitId":12390,
          "id":"16069",
          "CourseName":"ARK102U_ARKEOLOJİK ALAN YÖNETİMİ",
          "FieldId":8,
          "field":"TARİH",
        "query": {
            "span_near" : {
                "clauses" : [
                    { "span_term" : { "title" : "dünya" } },
                    { "span_term" : { "title" : "mirası" } },
                    { "span_term" : { "title" : "sözleşmesi" } }
                ],
                "slop" : 0,
                "in_order" : true
            }
        }
    }
    '
    
  • Percolate a documment:

    curl -XGET 'localhost:9200/my-index/_search?pretty' -H 'Content-Type: application/json' -d'
    {
        "query" : {
            "percolate" : {
                "field" : "query",
                "document" : {
                    "title" : "Arkeoloji, arkeolojik yöntemlerle ortaya çıkarılmış kültürleri, dünya mirası sözleşmesi sosyoloji, coğrafya, tarih, etnoloji gibi birçok bilim dalından yararlanarak araştıran ve inceleyen bilim dalıdır. Türkçeye yanlış bir şekilde> "kazıbilim" olarak çevrilmiş olsa da kazı, arkeolojik araştırma yöntemlerinden sadece bir tanesidir."
                }
            }
        },
    
        "highlight": {
          "fields": {
            "title": {}
          }
        }
    }
    '
    
  • I have this code until now:

    import json
    from elasticsearch_dsl import (
    DocType,
    Integer,
    Percolator,
    Text,
    )
    
    # Read the json File
    json_data = open('titles.json').read()
    data = json.loads(json_data)
    
    docs = data['response']['docs']
    
    # Creating a elasticsearch connection
    # connections.create_connection(hosts=['localhost'], port=['9200'], timeout=20)
    """
    curl -XPUT 'localhost:9200/my-index?pretty' -H 'Content-Type: application/json' -d'
    {
        "mappings": {
            "_doc": {
                "properties": {
                    "title": {
                        "type": "text"
                    },
                    "query": {
                        "type": "percolator"
                    }
                }
            }
        }
    }
    '
    
    """
    
    class Documment(DocType):
        course_id = Integer()
        unit_id = Integer()
        # title = Text()
        id = Integer()
        course_name = Text()
        field_id = Integer()
        field = Text()
    
    
        class Meta:
            index = 'titles_index'
    
    
                    properties={
                        'title': Text(),
                        'query': Percolator()
                     }
    
    """
        "query": {
            "span_near" : {
                "clauses" : [
                    { "span_term" : { "title" : "dünya" } },
                    { "span_term" : { "title" : "mirası" } },
                    { "span_term" : { "title" : "sözleşmesi" } }
                ],
                "slop" : 0,
                "in_order" : true
            }
        }
    
    """
    
    for doc in docs:
    
        terms = docs['title'].split(“ ”)
        course_id = docs['CourseId']
        unit_id = docs['UnitId']
        id = docs['id']
        course_name = docs['CourseName']
        field_id = docs['FieldId']
        field = docs['field']
    

    UPDATE: Thank you for the answer, i have this now:

    import json
    
    from elasticsearch_dsl import (
        connections,
        DocType,
        Mapping,
        Percolator,
        Text
    )
    from elasticsearch_dsl.query import (
        SpanNear,
        SpanTerm
    )
    from elasticsearch import Elasticsearch
    
    # Read the json File
    json_data = open('titles.json').read()
    data = json.loads(json_data)
    
    docs = data['response']['docs']
    
    
    # creating a new default elasticsearch connection
    connections.configure(
        default={'hosts': 'localhost:9200'},
    )
    
    
    class Document(DocType):
        title = Text()
        query = Percolator()
    
        class Meta:
            index = 'title-index'
            doc_type = '_doc'
    
        def save(self, **kwargs):
            return super(Document, self).save(**kwargs)
    
    
    # create the mappings in elasticsearch
    Document.init()
    
    # index the query
    for doc in docs:
        terms = doc['title'].split(" ")
        clauses = []
        for term in terms:
            field = SpanTerm(title=term)
            clauses.append(field)
        query = SpanNear(clauses=clauses)
        item = Document(title=doc['title'],query=query)
        item.save()
    

    It is working fine, but i have two goals now:

  • I'm getting the next error after indexing a randome number of items in the dict:
  • elasticsearch.exceptions.AuthorizationException: TransportError(403, 
    'cluster_block_exception', 'blocked by: [FORBIDDEN/12/index read-only 
    / allow delete (api)];')
    

    I know i can solve this problem using this command: curl -XPUT -H "Content-Type: application/json" http://localhost:9200/_all/_settings -d '{"index.blocks.read_only_allow_delete": null}'

    UPDATE Finally i solved it deleting the data folder.

    But now i'm making search in the index and i don't get anything:

    >>> text='Arkeoloji, arkeolojik yöntemlerle ortaya çıkarılmış kültürleri, dünya mirası sözleşmesi sosyoloji, coğrafya, tarih, etnoloji gibi birçok bilim dalından yararlanarak araştıran ve inceleyen bilim dalıdır. Türkçeye yanlış bir şekilde> "kazıbilim" olarak çevrilmiş olsa da kazı, arkeolojik araştırma yöntemlerinden sadece bir tanesidir.'
    >>> s = Search().using(client).query("percolate", field='query', document={'title': text}).highlight('title')
    >>> print(s.to_dict())
    {'query': {'percolate': {'field': 'query', 'document': {'title': 'Arkeoloji, arkeolojik yöntemlerle ortaya çıkarılmış kültürleri, dünya mirası sözleşmesi sosyoloji, coğrafya, tarih, etnoloji gibi birçok bilim dalından yararlanarak araştıran ve inceleyen bilim dalıdır. Türkçeye yanlış bir şekilde> "kazıbilim" olarak çevrilmiş olsa da kazı, arkeolojik araştırma yöntemlerinden sadece bir tanesidir.'}}}, 'highlight': {'fields': {'title': {}}}}
    >>> response = s.execute()
    >>> response
    <Response: {}>
    

    And this is my trying with curl :

     curl -XGET 'localhost:9200/title-index/_search?pretty' -H 'Content-Type: application/json' -d '{  
        "query" : {        
            "percolate" : {       
                "field" : "query",
                "document" : {
                    "title" : "Arkeoloji, arkeolojik yöntemlerle ortaya çıkarılmış kültürleri, dünya mirası sözleşmesi sosyoloji, coğrafya, tarih, etnoloji gibi birçok bilim dalından yararlanarak araştıran ve inceleyen bilim dalıdır. Türkçeye yanlış bir şekilde> "kazıbilim" olarak çevrilmiş olsa da kazı, arkeolojik araştırma yöntemlerinden sadece bir tanesidir."
                }
            }
        },            
        "highlight": {
          "fields": {  
            "title": {}
          }
        }
    }'
    {
      "took" : 3,
      "timed_out" : false,
      "_shards" : {
        "total" : 5,
        "successful" : 5,
        "skipped" : 0,
        "failed" : 0
      },
      "hits" : {
        "total" : 0,
        "max_score" : null,
        "hits" : [ ]
      }
    }
    

    I'm getting variable stats but not results:

    >>> response.to_dict()
    {'took': 9, 'timed_out': False, '_shards': {'total': 5, 'successful': 5, 'skipped': 0, 'failed': 0}, 'hits': {'total': 0, 'max_score': None, 'hits': []}}
    >>> response
    {'took': 12, 'timed_out': False, '_shards': {'total': 5, 'successful': 5, 'skipped': 0, 'failed': 0}, 'hits': {'total': 0, 'max_score': None, 'hits': []}}
    >>> response
    {'took': 12, 'timed_out': False, '_shards': {'total': 5, 'successful': 5, 'skipped': 0, 'failed': 0}, 'hits': {'total': 0, 'max_score': None, 'hits': []}}
    

    Can anyone help me?


    The first step is correct, ie the mapping is correct. But then, you need to first index a query, that's the whole point of percolation. So let's index your query:

    curl -XPUT 'localhost:9200/my-index/_doc/my-span-query?refresh&pretty' -H 'Content-Type: application/json' -d '{           
        "query": {
            "span_near" : {
                "clauses" : [
                    { "span_term" : { "title" : "dünya" } },
                    { "span_term" : { "title" : "mirası" } },
                    { "span_term" : { "title" : "sözleşmesi" } }
                ],
                "slop" : 0,
                "in_order" : true
            }
        }
    }'
    

    Then the idea is to find out which query would match the document you're percolating, so let's percolate a document:

    curl -XGET 'localhost:9200/my-index/_search?pretty' -H 'Content-Type: application/json' -d '{
        "query" : {
            "percolate" : {
                "field" : "query",
                "document" : {
                    "title" : "Arkeoloji, arkeolojik yöntemlerle ortaya çıkarılmış kültürleri, dünya mirası sözleşmesi sosyoloji, coğrafya, tarih, etnoloji gibi birçok bilim dalından yararlanarak araştıran ve inceleyen bilim dalıdır. Türkçeye yanlış bir şekilde> "kazıbilim" olarak çevrilmiş olsa da kazı, arkeolojik araştırma yöntemlerinden sadece bir tanesidir."
                }
            }
        },
        "highlight": {
          "fields": {
            "title": {}
          }
        }
    }'
    

    And you would get this response with highlighting where you can see that my-span-query matches the given document:

    {
      "took": 104,
      "timed_out": false,
      "_shards": {
        "total": 5,
        "successful": 5,
        "skipped": 0,
        "failed": 0
      },
      "hits": {
        "total": 1,
        "max_score": 0.8630463,
        "hits": [
          {
            "_index": "my-index",
            "_type": "_doc",
            "_id": "my-span-query",
            "_score": 0.8630463,
            "_source": {
              "query": {
                "span_near": {
                  "clauses": [
                    {
                      "span_term": {
                        "title": "dünya"
                      }
                    },
                    {
                      "span_term": {
                        "title": "mirası"
                      }
                    },
                    {
                      "span_term": {
                        "title": "sözleşmesi"
                      }
                    }
                  ],
                  "slop": 0,
                  "in_order": true
                }
              }
            },
            "fields": {
              "_percolator_document_slot": [
                0
              ]
            },
            "highlight": {
              "title": [
                "Arkeoloji, arkeolojik yöntemlerle ortaya çıkarılmış kültürleri, <em>dünya</em> <em>mirası</em> <em>sözleşmesi</em> sosyoloji, coğrafya"
              ]
            }
          }
        ]
      }
    }
    

    UPDATE

    The same thing using elasticsearch-py-dsl :

    from elasticsearch_dsl import DocType, Text, Percolator
    from elasticsearch import Elasticsearch
    
    class Document(DocType):
        title = Text()
        query = Percolator()
    
        class Meta:
            index = 'my-index'
    
        def save(self, ** kwargs):
            return super(Document, self).save(** kwargs)
    
    # 1a. create the mappings in elasticsearch
    Document.init()
    
    # 1b. or another alternative way of saving the mapping
    query_mapping = elasticsearch_dsl.Mapping('_doc')
    query_mapping.field('title', 'text')
    query_mapping.field('query', 'percolator')
    query_mapping.save('my-index')
    
    # 2. index the query
    query = Document(query={...your span query here...})
    query.save()
    
    # 3. send the percolate query
    client = Elasticsearch()
    response = client.search(
        index="my-index",
        body={
          "query" : {
            "percolate" : {
                "field" : "query",
                "document" : {
                    "title" : "Arkeoloji, arkeolojik yöntemlerle ortaya çıkarılmış kültürleri, dünya mirası sözleşmesi sosyoloji, coğrafya, tarih, etnoloji gibi birçok bilim dalından yararlanarak araştıran ve inceleyen bilim dalıdır. Türkçeye yanlış bir şekilde> "kazıbilim" olarak çevrilmiş olsa da kazı, arkeolojik araştırma yöntemlerinden sadece bir tanesidir."
                }
            }
        },
        "highlight": {
          "fields": {
            "title": {}
          }
        }
      }
    )
    

    UPDATE 2

    There's is no reason to also store the title along with the query, you only need to store the query, so your code should look like this instead:

    # index the query
    for doc in docs:
        terms = doc['title'].split(" ")
        clauses = []
        for term in terms:
            field = SpanTerm(title=term)
            clauses.append(field)
        query = SpanNear(clauses=clauses)
        item = Document(query=query)         <-- change this line
        item.save()
    
    链接地址: http://www.djcxy.com/p/41438.html

    上一篇: 如何创建一个可模拟的类来连接到mongoDB?

    下一篇: 用elasticsearch索引和渗透文档