8

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"
                }
            }
        }
    }
}
'
  1. 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
            }
        }
    }
    '
    
  2. 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:

  1. 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?

1 Answer 1

4
+100

The first step is correct, i.e. 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()
33
  • I'm sorry, but i know how do this; i need do the same thing but using elastic-search-dsl-py.
    – SalahAdDin
    Commented Mar 28, 2018 at 6:04
  • Well, the second step (i.e. indexing the query) was not correct and could not have worked that way. Anyway, let me update my answer and add some python in there
    – Val
    Commented Mar 28, 2018 at 6:14
  • I've added the comments before each step, it's pretty straightforward and does the same as each curl command above, 1) create the mapping for the percolator field, 2) index the query, 3) percolate a sample document.
    – Val
    Commented Mar 28, 2018 at 7:06
  • How can i index all documents in my dictionary?
    – SalahAdDin
    Commented Mar 28, 2018 at 7:15
  • I got it, whit the second way i get a properly mapping for _doc, but with the first documment i'm getting a mapping for doc, why?
    – SalahAdDin
    Commented Mar 28, 2018 at 9:00

Not the answer you're looking for? Browse other questions tagged or ask your own question.