indexa 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: fda7cc36eb4e16b6f702cef60afe13424ff6ea04
4
+ data.tar.gz: 26dd0ab1cb92169f6c7349a7c693e4835c44f8cb
5
+ SHA512:
6
+ metadata.gz: 75e85dfae2fe15fc80deb2b30a149e2258610592c5e8590b10820a64a7e6c959416750f4c3e56eca98faf3847841e8ffecb13e050c14d07d9fa974efcfcab734
7
+ data.tar.gz: 2bef7ce80d49c37decda3166f268beb4b004b07979fe38f44c53b3098a78983917d36ba0d68465ac189082f17d5a937c473994c66b99250266e92cff3dd9b068
@@ -0,0 +1,3 @@
1
+ dump.rdb
2
+ .gs
3
+
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2012 Julián Porta
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
@@ -0,0 +1,17 @@
1
+ indexa
2
+ ====
3
+
4
+ Indexa indexes an array of words in a redis backend
5
+
6
+ Description
7
+ -----------
8
+
9
+ Indexa indexes an array of words in a redis backend to be searched by Busca, the simple redis search
10
+
11
+ ## Installation
12
+
13
+ As usual, you can install it using rubygems.
14
+
15
+ ```
16
+ $ gem install indexa
17
+ ```
@@ -0,0 +1,16 @@
1
+ # encoding: utf-8
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = "indexa"
5
+ s.version = "0.0.1"
6
+ s.summary = "Indexa indexes an array of words in a redis backend"
7
+ s.description = "Indexa indexes an array of words in a redis backend to be searched by Busca, the simple redis search"
8
+ s.authors = ["Julián Porta"]
9
+ s.email = ["julian@porta.sh"]
10
+ s.homepage = "https://github.com/Porta/indexa"
11
+ s.files = `git ls-files`.split("\n")
12
+ s.license = "MIT"
13
+ s.add_development_dependency "cutest", '~> 1.2'
14
+ s.add_runtime_dependency "redic", '~> 1.4'
15
+ s.add_runtime_dependency "msgpack", '~> 0.5'
16
+ end
@@ -0,0 +1,64 @@
1
+ require 'msgpack'
2
+ require 'redic'
3
+
4
+
5
+ class Indexa
6
+
7
+ NAMESPACE = 'Busca' #TODO: Confirm gem name
8
+ LUA_CACHE = Hash.new { |h, k| h[k] = Hash.new }
9
+ LUA_INDEX = File.expand_path("./lib/lua/index.lua")
10
+ LUA_REMOVE = File.expand_path("./lib/lua/remove.lua")
11
+
12
+ def initialize(namespace = NAMESPACE, opts = {})
13
+ @namespace = namespace
14
+ redis = opts[:redis] || Redic.new
15
+ end
16
+
17
+ def add(document_id, words)
18
+ index_id = script( LUA_INDEX, 0,
19
+ @namespace.to_msgpack,
20
+ document_id.to_msgpack,
21
+ words.to_msgpack
22
+ )
23
+ return index_id
24
+ end
25
+
26
+ def remove(id)
27
+ result = script( LUA_REMOVE, 0,
28
+ @namespace.to_msgpack,
29
+ id.to_msgpack
30
+ )
31
+ return result
32
+ end
33
+
34
+ def redis
35
+ @redis ||= Redic.new
36
+ end
37
+
38
+
39
+ protected
40
+
41
+ def key(name)
42
+ Nido.new(NAMESPACE)[name]
43
+ end
44
+
45
+ def redis=(redis)
46
+ @redis = redis
47
+ end
48
+
49
+ def script(file, *args)
50
+ cache = LUA_CACHE[redis.url]
51
+
52
+ if cache.key?(file)
53
+ sha = cache[file]
54
+ else
55
+ src = File.read(file)
56
+ sha = redis.call("SCRIPT", "LOAD", src)
57
+
58
+ cache[file] = sha
59
+ end
60
+
61
+ redis.call("EVALSHA", sha, *args)
62
+ end
63
+
64
+ end
@@ -0,0 +1,36 @@
1
+ local namespace = cmsgpack.unpack(ARGV[1])
2
+ local document_id = cmsgpack.unpack(ARGV[2])
3
+ local words = cmsgpack.unpack(ARGV[3])
4
+
5
+ local function check_for_vacants()
6
+ local id = redis.call('RPOP', namespace .. ':vacants')
7
+ return id
8
+ end
9
+
10
+ local function save(document_id, words)
11
+ -- first try to get one available id from the vacants list
12
+ local id = check_for_vacants()
13
+
14
+ if id == false then
15
+ id = redis.call('INCR', namespace .. ':document:ids')
16
+ end
17
+
18
+ redis.call('SET', namespace .. ':document:' .. id, document_id)
19
+
20
+ return id
21
+ end
22
+
23
+
24
+ local function index(words, id)
25
+ for i, word in pairs(words) do
26
+ redis.call('SETBIT', namespace .. ':' .. word, id, 1)
27
+ redis.call('RPUSH', namespace .. ':document:' .. id .. ':words', word)
28
+ end
29
+ end
30
+
31
+
32
+ local id = save(document_id, words)
33
+
34
+ index(words, id)
35
+
36
+ return id
@@ -0,0 +1,33 @@
1
+ local namespace = cmsgpack.unpack(ARGV[1])
2
+ local id = cmsgpack.unpack(ARGV[2])
3
+
4
+
5
+ local function get_words(id)
6
+ local words = redis.call('LRANGE', namespace .. ':document:' .. id .. ':words', 0, -1)
7
+ return words
8
+ end
9
+
10
+ local function set_new_vacants(id)
11
+ local id = redis.call('RPUSH', namespace .. ':vacants', id)
12
+ return id
13
+ end
14
+
15
+ local function delete(id)
16
+ -- add document id to vacants list
17
+ set_new_vacants(id)
18
+ redis.call('DEL', namespace .. ':document:' .. id)
19
+ end
20
+
21
+ local function remove_from_index(words, id)
22
+ for i, word in pairs(words) do
23
+ redis.call('SETBIT', namespace .. ':' .. word, id, 0)
24
+ end
25
+ end
26
+
27
+
28
+ local words = get_words(id)
29
+ delete(id)
30
+
31
+ remove_from_index(words, id)
32
+
33
+ return true
@@ -0,0 +1,2 @@
1
+ test:
2
+ cutest ./tests/*_test.rb
@@ -0,0 +1,25 @@
1
+ require File.expand_path("../lib/indexa", File.dirname(__FILE__))
2
+
3
+ scope do
4
+ setup do
5
+ document = %w(this is some document that I've indexed)
6
+ indexer = Indexa.new
7
+ indexer.redis.call('flushdb')
8
+ [indexer, document]
9
+ end
10
+
11
+ test "index a document and get it's id" do |indexer, document|
12
+ document_id = indexer.add(5, document)
13
+ assert_equal document_id, 1
14
+ end
15
+
16
+ test "index two documents" do |indexer, document|
17
+ first = indexer.add(3, document)
18
+ second = indexer.add(7, %w(uno dos tres cuatro cinco seis))
19
+ assert_equal first, 1
20
+ assert_equal second, 2
21
+ end
22
+
23
+
24
+
25
+ end
@@ -0,0 +1,36 @@
1
+ require File.expand_path("../lib/indexa", File.dirname(__FILE__))
2
+
3
+ scope do
4
+ setup do
5
+ document = %w(this is some document that I've indexed)
6
+ indexer = Indexa.new
7
+ indexer.redis.call('flushdb')
8
+ [indexer, document]
9
+ end
10
+
11
+ test "delete a document from index" do |indexer, document|
12
+ first = indexer.add(1, document)
13
+ second = indexer.add(2, %w(altas llantas tiene el gato))
14
+ indexer.remove(second)
15
+ assert_equal indexer.redis.call('GET', 'Busca:document:1'), first.to_s
16
+ assert_equal indexer.redis.call('GET', 'Busca:document:2'), nil
17
+ end
18
+
19
+ test "should vacant an id upon document deletion" do |indexer, document|
20
+ first = indexer.add(1, document)
21
+ second = indexer.add(2, %w(altas llantas tiene el gato))
22
+ indexer.remove(second)
23
+ assert_equal indexer.redis.call('GET', 'Busca:document:2'), nil
24
+ assert_equal indexer.redis.call('LINDEX', 'Busca:vacants', 0), "2"
25
+ end
26
+
27
+ test "should use the vacant id on new document index" do |indexer, document|
28
+ first = indexer.add(1, document)
29
+ assert_equal indexer.redis.call('GET', 'Busca:document:1'), first.to_s
30
+ indexer.redis.call('RPUSH', 'Busca:vacants', 3)
31
+ foo = %w(My name is julian porta and Im a good person)
32
+ second = indexer.add(3, foo)
33
+ assert_equal indexer.redis.call('GET', 'Busca:document:3'), second.to_s
34
+ end
35
+
36
+ end
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: indexa
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Julián Porta
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-06-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: cutest
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.2'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: redic
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.4'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.4'
41
+ - !ruby/object:Gem::Dependency
42
+ name: msgpack
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.5'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.5'
55
+ description: Indexa indexes an array of words in a redis backend to be searched by
56
+ Busca, the simple redis search
57
+ email:
58
+ - julian@porta.sh
59
+ executables: []
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - ".gitignore"
64
+ - LICENSE
65
+ - README.md
66
+ - indexa.gemspec
67
+ - lib/indexa.rb
68
+ - lib/lua/index.lua
69
+ - lib/lua/remove.lua
70
+ - makefile
71
+ - tests/indexa_test.rb
72
+ - tests/remove_test.rb
73
+ homepage: https://github.com/Porta/indexa
74
+ licenses:
75
+ - MIT
76
+ metadata: {}
77
+ post_install_message:
78
+ rdoc_options: []
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ requirements: []
92
+ rubyforge_project:
93
+ rubygems_version: 2.4.6
94
+ signing_key:
95
+ specification_version: 4
96
+ summary: Indexa indexes an array of words in a redis backend
97
+ test_files: []