Class: DirectedEdge::Item

Inherits:
Resource show all
Defined in:
lib/directed_edge.rb

Overview

Represents an item in a Directed Edge database. Items can be products, pages or users, for instance. Usually items groups are differentiated from one another by a set of tags that are provided.

For instance, a user in the Directed Edge database could be modeled as:

user = DirectedEdge::Item.new(database, 'user_1')
user.add_tag('user')
user.save

Similarly a product could be:

product = DirectedEdge::Item.new(database, 'product_1')
product.add_tag('product')
product['price'] = '$42'
product.save

Note here that items have tags and properties. Tags are a free-form set of text identifiers that can be associated with an item, e.g. “user”, “product”, “page”, “science fiction”, etc.

Properties are a set of key-value pairs associated with the item. For example, product['price'] = '$42', or user['first name'] = 'Bob'.

If we wanted to link the user to the product, for instance, indicating that the user had purchased the product we can use:

user.link_to(product)
user.save

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(database, id) ⇒ Item

Creates a handle to an item in the DirectedEdge database which may be manipulated locally and then saved back to the database by calling save.



323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
# File 'lib/directed_edge.rb', line 323

def initialize(database, id)
  @database = database

  @id = id
  @links = CollectionHash.new(Hash)
  @tags = Set.new
  @preselected = []
  @blacklisted = Set.new
  @properties = {}

  @links_to_remove = CollectionHash.new(Set)
  @tags_to_remove = Set.new
  @preselected_to_remove = Set.new
  @blacklisted_to_remove = Set.new
  @properties_to_remove = Set.new

  @resource = @database.resource[URI.escape(@id)]
  @cached = false
end

Instance Attribute Details

#idObject (readonly)

The unique item identifier used by the database and specified in the item’s constructor.



318
319
320
# File 'lib/directed_edge.rb', line 318

def id
  @id
end

Instance Method Details

#==(other) ⇒ Object

Returns true if the other item is the same. The item given can either be a string or an item object.



346
347
348
349
350
351
352
# File 'lib/directed_edge.rb', line 346

def ==(other)
  if other.is_a?(Item)
    other.id == id
  else
    other.to_s == id
  end
end

#[](property_name) ⇒ Object

Returns the property for the name specified.



468
469
470
471
# File 'lib/directed_edge.rb', line 468

def [](property_name)
  read
  @properties[property_name]
end

#[]=(property_name, value) ⇒ Object

Assigns value to the given property_name.

This will not be written back to the database until save is called.



477
478
479
480
# File 'lib/directed_edge.rb', line 477

def []=(property_name, value)
  @properties_to_remove.delete(property_name)
  @properties[property_name] = value
end

#add_blacklisted(item) ⇒ Object



567
568
569
570
# File 'lib/directed_edge.rb', line 567

def add_blacklisted(item)
  @blacklisted_to_remove.delete(item)
  @blacklisted.add(item)
end

#add_preselected(item) ⇒ Object



557
558
559
560
# File 'lib/directed_edge.rb', line 557

def add_preselected(item)
  @preselected_to_remove.delete(item)
  @preselected.push(item)
end

#add_tag(tag) ⇒ Object

Adds a tag to this item.

The changes will not be reflected in the database until save is called.



543
544
545
546
# File 'lib/directed_edge.rb', line 543

def add_tag(tag)
  @tags_to_remove.delete(tag)
  @tags.add(tag)
end

#blacklistedObject

Returns a set of items that should not ever be recommended for this item.



454
455
456
457
# File 'lib/directed_edge.rb', line 454

def blacklisted
  read
  @blacklisted
end

#clear_property(property_name) ⇒ Object

Remove the given property_name.



484
485
486
487
# File 'lib/directed_edge.rb', line 484

def clear_property(property_name)
  @properties_to_remove.add(property_name) unless @cached
  @properties.delete(property_name)
end

#create(links = {}, tags = Set.new, properties = {}) ⇒ Object

Creates an item if it does not already exist in the database or overwrites an existing item if one does.

This has been deprecated as it’s not set up to properly support link types. use new / save instead.



366
367
368
369
370
371
372
373
374
375
376
377
# File 'lib/directed_edge.rb', line 366

def create(links={}, tags=Set.new, properties={})
  warn 'DirectedEdge::Item::create has been deprecated. Use new / save instead.'
  @links[''] = links
  @tags = tags
  @properties = properties

  # Here we pretend that it's cached since this is now the authoritative
  # copy of the values.

  @cached = true
  save
end

#destroyObject

Removes an item from the database, including deleting all links to and from this item.



492
493
494
# File 'lib/directed_edge.rb', line 492

def destroy
  @resource.delete
end

Creates a link from this item to other.

Weighted links are typically used to encode ratings. For instance, if a user has rated a given product that can be specified via:

user = DirectedEdge::Item(database, 'user_1')
product = DirectedEdge::Item(database, 'product_1') # preexisting item
user.link_to(product, 5)
user.save

If no link is specified then a tradtional, unweighted link will be created. This is typical to, for instance, incidate a purchase or click from a user to a page or item.

Weights may be in the range of 1 to 10.

Note that ‘other’ must exist in the database or must be saved before this item is saved. Otherwise the link will be ignored as the engine tries to detect ‘broken’ links that do not terminate at a valid item.

Raises:

  • (RangeError)


516
517
518
519
520
# File 'lib/directed_edge.rb', line 516

def link_to(other, weight=0, type='')
  raise RangeError if (weight < 0 || weight > 10)
  @links_to_remove[type.to_s].delete(other)
  @links[type.to_s][other.to_s] = weight
end

Returns a set of items that are linked to from this item.



433
434
435
436
# File 'lib/directed_edge.rb', line 433

def links(type='')
  read
  @links[type.to_s]
end

#nameObject

Returns the item’s ID.



356
357
358
# File 'lib/directed_edge.rb', line 356

def name
  @id
end

#preselectedObject

Returns an ordered list of items that are preselected for this item.



447
448
449
450
# File 'lib/directed_edge.rb', line 447

def preselected
  read
  @preselected
end

#propertiesObject

Returns a hash of all of this item’s properties.



461
462
463
464
# File 'lib/directed_edge.rb', line 461

def properties
  read
  @properties
end

Returns the list of items recommended for this item, usually a user. Unlike “related” this does not include items linked from this item. If any tags are specified, only items which have one or more of the specified tags will be returned.

Parameters that may be passed in include:

  • :exclude_linked (true / false)

  • :max_results (integer)

This will not reflect any unsaved changes to items.



609
610
611
612
613
614
615
616
617
618
# File 'lib/directed_edge.rb', line 609

def recommended(tags=Set.new, params={})
  params = normalize_params(params)
  params['tags'] = tags.to_a.join(',')
  params.key?('excludeLinked') || params['excludeLinked'] = 'true'
  if params['includeProperties'] == 'true'
    property_hash_from_document(read_document('recommended', params), 'recommended')
  else
    list_from_document(read_document('recommended', params), 'recommended')
  end
end

Returns the list of items related to this one. Unlike “recommended” this may include items which are directly linked from this item. If any tags are specified, only items which have one or more of the specified tags will be returned.

Parameters that may be passed in include:

  • :exclude_linked (true / false)

  • :max_results (integer)

This will not reflect any unsaved changes to items.



588
589
590
591
592
593
594
595
596
# File 'lib/directed_edge.rb', line 588

def related(tags=Set.new, params={})
  params = normalize_params(params)
  params['tags'] = tags.to_a.join(',')
  if params['includeProperties'] == 'true'
    property_hash_from_document(read_document('related', params), 'related')
  else
    list_from_document(read_document('related', params), 'related')
  end
end

#reloadObject

Reloads (or loads) the item from the database. Any unsaved changes will will be discarded.



414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
# File 'lib/directed_edge.rb', line 414

def reload
  @links.clear
  @tags.clear
  @preselected.clear
  @blacklisted.clear
  @properties.clear

  @links_to_remove.clear
  @tags_to_remove.clear
  @preselected_to_remove.clear
  @blacklisted_to_remove.clear
  @properties_to_remove.clear

  @cached = false
  read
end

#remove_blacklisted(item) ⇒ Object



572
573
574
575
# File 'lib/directed_edge.rb', line 572

def remove_blacklisted(item)
  @blacklisted_to_remove.add(item) unless @cached
  @blacklisted.delete(item)
end

#remove_preselected(item) ⇒ Object



562
563
564
565
# File 'lib/directed_edge.rb', line 562

def remove_preselected(item)
  @preselected_to_remove.add(item) unless @cached
  @preselected.delete(item)
end

#remove_tag(tag) ⇒ Object

Removes a tag from this item.

The changes will not be reflected in the database until save is called.



552
553
554
555
# File 'lib/directed_edge.rb', line 552

def remove_tag(tag)
  @tags_to_remove.add(tag) unless @cached
  @tags.delete(tag)
end

#saveObject

Writes all changes to links, tags and properties back to the database and returns this item.



382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
# File 'lib/directed_edge.rb', line 382

def save
  if @cached
    put(complete_document)
  else

    # The web services API allows to add or remove things incrementally.
    # Since we're not in the cached case, let's check to see which action(s)
    # are appropriate.

    put(complete_document, 'add')

    ### CHECKING LINKS_TO_REMOVE.EMPTY? ISN'T CORRECT ANYMORE

    if !@links_to_remove.empty? ||
        !@tags_to_remove.empty? ||
        !@preselected_to_remove.empty? ||
        !@blacklisted_to_remove.empty? ||
        !@properties_to_remove.empty?
      put(removal_document, 'remove')
      @links_to_remove.clear
      @tags_to_remove.clear
      @properties_to_remove.clear
      @preselected_to_remove.clear
      @blacklisted_to_remove.clear
    end
  end
  self
end

#tagsObject

Returns a set containing all of this item’s tags.



440
441
442
443
# File 'lib/directed_edge.rb', line 440

def tags
  read
  @tags
end

#to_sObject

Returns the ID of the item.



622
623
624
# File 'lib/directed_edge.rb', line 622

def to_s
  @id
end

#to_xmlObject

Returns an XML representation of the item as a string not including the usual document regalia, e.g. starting with <item> (used for exporting the item to a file)



630
631
632
# File 'lib/directed_edge.rb', line 630

def to_xml
  insert_item(REXML::Document.new).to_s
end

Deletes a link from this item to other.

The changes will not be reflected in the database until save is called.



526
527
528
529
# File 'lib/directed_edge.rb', line 526

def unlink_from(other, type='')
  @links_to_remove[type.to_s].add(other.to_s) unless @cached
  @links[type.to_s].delete(other.to_s)
end

#weight_for(other, type = '') ⇒ Object

If there is a link for “other” then it returns the weight for the given item. Zero indicates that no weight is assigned.



534
535
536
537
# File 'lib/directed_edge.rb', line 534

def weight_for(other, type='')
  read
  @links[type.to_s][other.to_s]
end